<!DOCTYPE html>


<html theme="dark" showBanner="true" hasBanner="false" > 
<link href="/blog/fontawesome/css/fontawesome.css" rel="stylesheet">
<link href="/blog/fontawesome/css/brands.css" rel="stylesheet">
<link href="/blog/fontawesome/css/solid.css" rel="stylesheet">
<script src="/blog/js/color.global.min.js" ></script>
<script src="/blog/js/load-settings.js" ></script>
<head>
  <meta charset="utf-8">
  
  
  

  
  <title>Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <link rel="preload" href="/blog/css/fonts/Roboto-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
  <link rel="preload" href="/blog/css/fonts/Roboto-Bold.ttf" as="font" type="font/ttf" crossorigin="anonymous">

  <meta name="description" content="从开始接触音频子系统到如今已经两个多月，说实话花费的时间的确有点长了。从今天起我们开始接触DRM，网上已经有很多优秀的关于DRM的文章了，因此我们学习直接去学习一些优秀的文章即可。后面有关DRM相关的文章我们会大量参考DRM (Direct Rendering Manager)。 一、DRM介绍1.1 DRM概述linux内核中包含两类图形显示设备驱动框架：  FB设备：Framebuffer图形">
<meta property="og:type" content="article">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="https://zyly2033.gitee.io/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E5%AD%90%E7%B3%BB%E7%BB%9F/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="从开始接触音频子系统到如今已经两个多月，说实话花费的时间的确有点长了。从今天起我们开始接触DRM，网上已经有很多优秀的关于DRM的文章了，因此我们学习直接去学习一些优秀的文章即可。后面有关DRM相关的文章我们会大量参考DRM (Direct Rendering Manager)。 一、DRM介绍1.1 DRM概述linux内核中包含两类图形显示设备驱动框架：  FB设备：Framebuffer图形">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282133526.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309052007549.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309041953326.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309091810756.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282320783.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282323537.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282323626.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309091810863.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282326620.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282307244.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282310791.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309091810235.svg+xml">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309101705583.svg">
<meta property="article:published_time" content="2023-09-11T12:23:16.258Z">
<meta property="article:modified_time" content="2023-09-10T12:46:21.640Z">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202308282133526.png">
  
    <link rel="alternate" href="/blog/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-32.png" sizes="32x32">
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-128.png" sizes="128x128">
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-180.png" sizes="180x180">
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-192.png" sizes="192x192">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-32.png" sizes="32x32">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-128.png" sizes="128x128">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-180.png" sizes="180x180">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-192.png" sizes="192x192">
  
  
<link rel="stylesheet" href="/blog/css/style.css">

<meta name="generator" content="Hexo 6.3.0"></head>

<body>
  
   
  <div id="main-grid" class="shadow   ">
    <div id="nav" class=""  >
      <navbar id="navbar">
  <nav id="title-nav">
    <a href="/blog/">
      <div id="vivia-logo">
        <div class="dot"></div>
        <div class="dot"></div>
        <div class="dot"></div>
        <div class="dot"></div>
      </div>
      <div>Hexo </div>
    </a>
  </nav>
  <nav id="main-nav">
    
      <a class="main-nav-link" href="/blog/">Home</a>
    
      <a class="main-nav-link" href="/blog/archives">Archives</a>
    
      <a class="main-nav-link" href="/blog/about">About</a>
    
  </nav>
  <nav id="sub-nav">
    <a id="theme-btn" class="nav-icon">
      <span class="light-mode-icon"><svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M438.5-829.913v-48q0-17.452 11.963-29.476 11.964-12.024 29.326-12.024 17.363 0 29.537 12.024t12.174 29.476v48q0 17.452-11.963 29.476-11.964 12.024-29.326 12.024-17.363 0-29.537-12.024T438.5-829.913Zm0 747.826v-48q0-17.452 11.963-29.476 11.964-12.024 29.326-12.024 17.363 0 29.537 12.024t12.174 29.476v48q0 17.452-11.963 29.476-11.964 12.024-29.326 12.024-17.363 0-29.537-12.024T438.5-82.087ZM877.913-438.5h-48q-17.452 0-29.476-11.963-12.024-11.964-12.024-29.326 0-17.363 12.024-29.537t29.476-12.174h48q17.452 0 29.476 11.963 12.024 11.964 12.024 29.326 0 17.363-12.024 29.537T877.913-438.5Zm-747.826 0h-48q-17.452 0-29.476-11.963-12.024-11.964-12.024-29.326 0-17.363 12.024-29.537T82.087-521.5h48q17.452 0 29.476 11.963 12.024 11.964 12.024 29.326 0 17.363-12.024 29.537T130.087-438.5Zm660.174-290.87-34.239 32q-12.913 12.674-29.565 12.174-16.653-.5-29.327-13.174-12.674-12.673-12.554-28.826.12-16.152 12.794-28.826l33-35q12.913-12.674 30.454-12.674t30.163 12.847q12.709 12.846 12.328 30.826-.38 17.98-13.054 30.653ZM262.63-203.978l-32 34q-12.913 12.674-30.454 12.674t-30.163-12.847q-12.709-12.846-12.328-30.826.38-17.98 13.054-30.653l33.239-31q12.913-12.674 29.565-12.174 16.653.5 29.327 13.174 12.674 12.673 12.554 28.826-.12 16.152-12.794 28.826Zm466.74 33.239-32-33.239q-12.674-12.913-12.174-29.565.5-16.653 13.174-29.327 12.673-12.674 28.826-13.054 16.152-.38 28.826 12.294l35 33q12.674 12.913 12.674 30.454t-12.847 30.163q-12.846 12.709-30.826 12.328-17.98-.38-30.653-13.054ZM203.978-697.37l-34-33q-12.674-12.913-13.174-29.945-.5-17.033 12.174-29.707t31.326-13.293q18.653-.62 31.326 13.054l32 34.239q11.674 12.913 11.174 29.565-.5 16.653-13.174 29.327-12.673 12.674-28.826 12.554-16.152-.12-28.826-12.794ZM480-240q-100 0-170-70t-70-170q0-100 70-170t170-70q100 0 170 70t70 170q0 100-70 170t-170 70Zm-.247-82q65.703 0 111.475-46.272Q637-414.544 637-480.247t-45.525-111.228Q545.95-637 480.247-637t-111.475 45.525Q323-545.95 323-480.247t45.525 111.975Q414.05-322 479.753-322ZM481-481Z"/></svg></span>
      <span class="dark-mode-icon"><svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M480.239-116.413q-152.63 0-258.228-105.478Q116.413-327.37 116.413-480q0-130.935 77.739-227.435t206.304-125.043q43.022-9.631 63.87 10.869t3.478 62.805q-8.891 22.043-14.315 44.463-5.424 22.42-5.424 46.689 0 91.694 64.326 155.879 64.325 64.186 156.218 64.186 24.369 0 46.978-4.946 22.609-4.945 44.413-14.076 42.826-17.369 62.967 1.142 20.142 18.511 10.511 61.054Q807.174-280 712.63-198.206q-94.543 81.793-232.391 81.793Zm0-95q79.783 0 143.337-40.217 63.554-40.218 95.793-108.283-15.608 4.044-31.097 5.326-15.49 1.283-31.859.805-123.706-4.066-210.777-90.539-87.071-86.473-91.614-212.092-.24-16.369.923-31.978 1.164-15.609 5.446-30.978-67.826 32.478-108.282 96.152Q211.652-559.543 211.652-480q0 111.929 78.329 190.258 78.329 78.329 190.258 78.329ZM466.13-465.891Z"/></svg></span>
    </a>
    
      <a id="nav-rss-link" class="nav-icon mobile-hide" href="/blog/atom.xml" title="RSS Feed">
        <svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M198-120q-25.846 0-44.23-18.384-18.384-18.385-18.384-44.23 0-25.846 18.384-44.23 18.384-18.385 44.23-18.385 25.846 0 44.23 18.385 18.384 18.384 18.384 44.23 0 25.845-18.384 44.23Q223.846-120 198-120Zm538.385 0q-18.846 0-32.923-13.769-14.076-13.769-15.922-33.23-8.692-100.616-51.077-188.654-42.385-88.039-109.885-155.539-67.5-67.501-155.539-109.885Q283-663.462 182.385-672.154q-19.461-1.846-33.23-16.23-13.769-14.385-13.769-33.846t14.076-32.922q14.077-13.461 32.923-12.23 120.076 8.692 226.038 58.768 105.961 50.077 185.73 129.846 79.769 79.769 129.846 185.731 50.077 105.961 58.769 226.038 1.231 18.846-12.538 32.922Q756.461-120 736.385-120Zm-252 0q-18.231 0-32.423-13.461t-18.653-33.538Q418.155-264.23 348.886-333.5q-69.27-69.27-166.501-84.423-20.077-4.462-33.538-18.961-13.461-14.5-13.461-33.346 0-19.076 13.884-33.23 13.884-14.153 33.115-10.922 136.769 15.384 234.384 112.999 97.615 97.615 112.999 234.384 3.231 19.23-10.538 33.115Q505.461-120 484.385-120Z"/></svg>
      </a>
    
    <div id="nav-menu-btn" class="nav-icon">
      <svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M177.37-252.282q-17.453 0-29.477-11.964-12.024-11.963-12.024-29.326t12.024-29.537q12.024-12.174 29.477-12.174h605.26q17.453 0 29.477 11.964 12.024 11.963 12.024 29.326t-12.024 29.537q-12.024 12.174-29.477 12.174H177.37Zm0-186.218q-17.453 0-29.477-11.963-12.024-11.964-12.024-29.326 0-17.363 12.024-29.537T177.37-521.5h605.26q17.453 0 29.477 11.963 12.024 11.964 12.024 29.326 0 17.363-12.024 29.537T782.63-438.5H177.37Zm0-186.217q-17.453 0-29.477-11.964-12.024-11.963-12.024-29.326t12.024-29.537q12.024-12.174 29.477-12.174h605.26q17.453 0 29.477 11.964 12.024 11.963 12.024 29.326t-12.024 29.537q-12.024 12.174-29.477 12.174H177.37Z"/></svg>
    </div>
  </nav>
</navbar>
<div id="nav-dropdown" class="hidden">
  <div id="dropdown-link-list">
    
      <a class="nav-dropdown-link" href="/blog/">Home</a>
    
      <a class="nav-dropdown-link" href="/blog/archives">Archives</a>
    
      <a class="nav-dropdown-link" href="/blog/about">About</a>
    
    
      <a class="nav-dropdown-link" href="/blog/atom.xml" title="RSS Feed">RSS</a>
     
    </div>
</div>
<script>
  let dropdownBtn = document.getElementById("nav-menu-btn");
  let dropdownEle = document.getElementById("nav-dropdown");
  dropdownBtn.onclick = function() {
    dropdownEle.classList.toggle("hidden");
  }
</script>
    </div>
    <div id="sidebar-wrapper">
      <sidebar id="sidebar">
  
    <div class="widget-wrap">
  <div class="info-card">
    <div class="avatar">
      
      <div class="img-dim"></div>
    </div>
    <div class="info">
      <div class="username">Your Name </div>
      <div class="dot"></div>
      <div class="subtitle">This is the subtitle </div>
      <div class="link-list">
        
          <a class="link-btn" target="_blank" rel="noopener" href="https://twitter.com" title="Twitter"><i class="fa-brands fa-twitter"></i></a>
        
          <a class="link-btn" target="_blank" rel="noopener" href="https://store.steampowered.com" title="Steam"><i class="fa-brands fa-steam"></i></a>
        
          <a class="link-btn" target="_blank" rel="noopener" href="https://github.com" title="GitHub"><i class="fa-brands fa-github"></i></a>
         
      </div>  
    </div>
  </div>
</div>

  
  <div class="sticky">
    
      



    
      

    
      
  <div class="widget-wrap">
    <div class="widget">
      <h3 class="widget-title">Archives</h3>
      
      
        <a class="archive-link" href="/blog/archives/2023/09 ">
          September 2023 
          <div class="archive-count">8 </div>
        </a>
      
    </div>
  </div>


    
      
  <div class="widget-wrap">
    <div class="widget">
      <h3 class="widget-title">Recent Posts</h3>
      <ul>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E5%AD%90%E7%B3%BB%E7%BB%9F/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%20plane/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%20framebuffer/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%20crtc/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
      </ul>
    </div>
  </div>

    
  </div>
</sidebar>
    </div>
    <div id="content-body">
       

<article id="post-rk3399/Rockchip RK3399 - DRM子系统" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  
    
   
  <div class="article-inner">
    <div class="article-main">
      <header class="article-header">
        
<div class="main-title-bar">
  <div class="main-title-dot"></div>
  
    
      <h1 class="p-name article-title" itemprop="headline name">
        Untitled
      </h1>
    
  
</div>

        <div class='meta-info-bar'>
          <div class="meta-info">
  <time class="dt-published" datetime="2023-09-11T12:23:16.258Z" itemprop="datePublished">2023-09-11</time>
</div>
          <div class="need-seperator meta-info">
            <div class="meta-cate-flex">
  
    Uncategorized 
   
</div>
  
          </div>
          <div class="wordcount need-seperator meta-info">
            21k words 
          </div>
        </div>
        
      </header>
      <div class="e-content article-entry" itemprop="articleBody">
        
          <p>从开始接触音频子系统到如今已经两个多月，说实话花费的时间的确有点长了。从今天起我们开始接触<code>DRM</code>，网上已经有很多优秀的关于<code>DRM</code>的文章了，因此我们学习直接去学习一些优秀的文章即可。后面有关<code>DRM</code>相关的文章我们会大量参考<a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/category_9281458.html"><code>DRM (Direct Rendering Manager)</code></a>。</p>
<h3 id="一、DRM介绍"><a href="#一、DRM介绍" class="headerlink" title="一、DRM介绍"></a>一、<code>DRM</code>介绍</h3><h4 id="1-1-DRM概述"><a href="#1-1-DRM概述" class="headerlink" title="1.1 DRM概述"></a>1.1 <code>DRM</code>概述</h4><p><code>linux</code>内核中包含两类图形显示设备驱动框架：</p>
<ul>
<li><code>FB</code>设备：<a target="_blank" rel="noopener" href="https://www.cnblogs.com/zyly/p/16146712.html"><code>Framebuffer</code></a>图形显示框架;</li>
<li><code>DRM</code>：直接渲染管理器（<code>Direct Rendering Manager</code>），是<code>linux</code>目前主流的图形显示框架；</li>
</ul>
<p>在实际场景中，具体选择哪一种图形设备驱动框架取决于我们自己的业务需求。</p>
<h5 id="1-1-1-Frambebuffer驱动"><a href="#1-1-1-Frambebuffer驱动" class="headerlink" title="1.1.1 Frambebuffer驱动"></a>1.1.1 <code>Frambebuffer</code>驱动</h5><p><code>Frambebuffer</code>驱动具有以下特征：</p>
<ul>
<li><p>直接控制显卡的帧缓冲区，提供基本的显卡输出功能；</p>
</li>
<li><p>使用一些内核数据结构和<code>API</code>来管理图形界面，并提供一组接口与用户空间的应用程序进行通信；</p>
</li>
<li><p>相对简单，适合于嵌入式系统或者不需要高性能图形的应用场景。</p>
</li>
</ul>
<h5 id="1-1-2-DRM驱动"><a href="#1-1-2-DRM驱动" class="headerlink" title="1.1.2 DRM驱动"></a>1.1.2 <code>DRM</code>驱动</h5><p>相比<code>FB</code>（<a target="_blank" rel="noopener" href="https://www.cnblogs.com/zyly/p/16146712.html"><code>Framebuffer</code></a>）架构，<code>DRM</code>更能适应当前日益更新的显示硬件；</p>
<ul>
<li>提供一种分离的图形驱动架构，将硬件驱动程序、内核模块和用户空间驱动程序进行分离；</li>
<li>支持多个应用程序同时访问显卡，并提供了更丰富的图形功能，例如硬件加速和<code>3D</code>加速；</li>
<li>提供了一些内核接口，可以让用户空间应用程序与驱动程序进行交互；</li>
<li>支持多显示器（<code>Display</code>）和多<code>GPU</code>的配置；</li>
</ul>
<p>总之，一句话，<code>DRM</code>是<code>Linux</code>目前主流的图形显示框架，相比<code>FB</code>架构，<code>DRM</code>更能适应当前日益更新的显示硬。尽管<code>FB</code>退出历史舞台，但是并未将其遗弃，而是集合到<code>DRM</code>中，供部分嵌入式设备使用。</p>
<p>有关<code>DRM</code>的发展历史可以参考这篇博客：<a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/article/details/88075520"><code>DRM (Direct Rendering Manager)</code> 的发展历史</a>。</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202308282133526.png" width='700px'/>

<h4 id="1-2-DRM框架"><a href="#1-2-DRM框架" class="headerlink" title="1.2 DRM框架"></a>1.2 <code>DRM</code>框架</h4><p>我们来看一下<code>DRM</code>子系统的软件架构：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309052007549.png" width="700px"/>

<p><code>DRM</code>框架从上到下依次为应用程序、<code>libdrm</code>、<code>DRM driver</code>、<code>HW</code>；</p>
<p>(1) 应用程序：上图中并没有画出；应用程序可以直接操纵<code>DRM</code>的<code>ioctl</code>进行显示相关操作，后来封装成了<code>libdrm</code>库，让用户可以更加方便的进行显示控制；</p>
<p>(2) <code>libdrm</code>：<code>lbdrm</code>是<code>DRM</code>框架提供的位于用户空间操作<code>DRM</code>的库，提供了<code>DRM</code>驱动的用户空间接口；对底层接口进行封装，向上层应用程序提供通用的<code>API</code>接口，本质上是对各种<code>ioctl</code>接口进行封装；</p>
<p>(3) <code>DRM core</code>：<code>DRM</code>核心层，由<code>GEM</code>和<code>KMS</code>组成；</p>
<ul>
<li><code>KMS</code>：<code>Kernel Mode Setting</code>，所谓内核显示模式设置，其实说白了就两件事：更新画面和设置显示参数；<ul>
<li>更新画面：显示<code>buffer</code>的切换，多图层的合成方式，以及每个图层的显示位置；</li>
<li>设置显示参数：包括分辨率、刷新率、电源状态（休眠唤醒）等；</li>
</ul>
</li>
<li><code>GEM</code>：<code>Graphic Execution Manager</code>（图形执行管理器），它提供了一种抽象的显存管理方式，使用户空间应用程序可以更方便地管理显存，而不需要了解底层硬件的细节；<ul>
<li>实际上，在DRM中包含两个内存管理器，<code>TTM</code>（<code>Translation Table Manager</code>）和<code>GEM</code>（<code>Graphic Execution Manager</code>），<code>TTM</code>是第一个开发的<code>DRM</code>内存管理器，关于<code>TTM</code>我们就不做过多的介绍了，知道有这么一个东西就好了。</li>
</ul>
</li>
</ul>
<p>(4) <code>HW</code>：硬件设备；</p>
<h5 id="1-2-1-KMS"><a href="#1-2-1-KMS" class="headerlink" title="1.2.1 KMS"></a>1.2.1 <code>KMS</code></h5><p><code>KMS</code>主要负责显示相关功能，在<code>DRM</code>中将其进行抽象，包括：<code>CRTC</code>、<code>ENCODER</code>、<code>CONNECTOR</code>、<code>PLANE</code>、<code>Framebuffer</code>、<code>VBLANK</code>、<code>property</code>；它们之间的关系如下图所示：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309041953326.png" width='700px'/>

<p>以<code>HDMI</code>接口为例说明，<code>Soc</code>内部一般包含一个<code>Display</code>模块，通过总线连接到<code>HDMI</code>接口上；</p>
<ul>
<li><code>Display</code>模块对应<code>CRTC</code>；</li>
<li><code>HDMI</code>接口对应<code>Connector</code>；</li>
<li><code>Framebuffer</code>对应的是显存部分；</li>
<li><code>Plane</code>是对<code>Framebuffer</code>进行描述的部分；</li>
<li><code>Encoder</code>是将像素转化为<code>HDMI</code>接口所需要的信号，一般<code>Encoder</code>和<code>Connector</code>放到一块初始化。</li>
</ul>
<h5 id="1-2-2-GEM"><a href="#1-2-2-GEM" class="headerlink" title="1.2.2 GEM"></a>1.2.2 <code>GEM</code></h5><p><code>GEM</code>主要负责显示<code>buffer</code>的分配和释放，在<code>DRM</code>中将其进行抽象，包括：<code>DUMP</code>、<code>PRIME</code>、<code>fence</code>；</p>
<h5 id="1-2-3-元素介绍"><a href="#1-2-3-元素介绍" class="headerlink" title="1.2.3 元素介绍"></a>1.2.3 元素介绍</h5><p>学习<code>DRM</code>驱动其实就是学习上面各个元素的实现及用法，如果你能掌握这些知识点，那么在编写<code>DRM</code>驱动的时候就能游刃有余。</p>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody><tr>
<td>元素</td>
<td>说明</td>
</tr>
<tr>
<td><code>CRTC</code></td>
<td>从<code>Framebuffer</code>中读取待显示的图像，并按照响应的格式输出给<code>encoder</code>，其主要承担的作用为<br>（1）配置适合显示的显示模式、分辨率、刷新率等参数，并输出相应的时序；<br>（2）扫描<code>Framebuffer</code>发送到一个或多个显示器；<br>（3）更新<code>Framebuffer</code>；<br>概括下就是，对显示器进行扫描，产生时序信号的模块、负责帧切换、电源控制、色彩调整等等。</td>
</tr>
<tr>
<td><code>ENCODER</code></td>
<td>编码器。它的作用就是将内存的<code>pixel</code>像素编码（转换）为显示器所需要的信号。<br>简单理解就是，如果需要将画面显示到不同的设备（<code>Display Device</code>）上，需要将画面转化为不同的电信号，例如<code>DVID</code>、<code>VGA</code>、<code>YPbPr</code>、<code>CVBS</code>、<code>MIPI</code>、<code>eDP</code> 等。<br/><code>Encoder</code>和<code>CRTC</code>之间的交互就是我们所说的<code>Mode Setting</code>，其中包含了前面提到的色彩模式、还有时序（<code>Timing</code>）等</td>
</tr>
<tr>
<td><code>CONNECTOR</code></td>
<td>连接器。它常常对应于物理连接器 (例如<code>VGA</code>,<code>DVI</code>, <code>FPD-Link</code>, <code>HDMI</code>, <code>DisplayPort</code>, <code>S-Video</code>等) ，它不是指物理线。<br>在<code>DRM</code>中，<code>Connector</code> 是一个抽象的数据结构，代表连接的显示设备，从<code>Connector</code>中可以得到当前物理连接的输出设备相关的信息 ；例如连接状态，<code>EDID</code>数据，<code>DPMS</code>状态、支持的视频模式等</td>
</tr>
<tr>
<td><code>PLANE</code></td>
<td>图层，实际输出的图像是多个图层叠加而成的，比如主图层、光标图层。其中有些图层由硬件加速模块生成，每个<code>CRTC</code>至少一个<code>plane</code>；<br><code>plane</code>一共有三种，分别是：<code>DRM_PLANE_TYPE_PRIMARY</code>、<code>DRM_PLANE_TYPE_OVERLAY</code>、<code>DRM_PLANE_TYPE_CURSOR</code>。这是配置<code>plane</code>的三个枚举，标注主图层、覆盖图层、光标图层；</td>
</tr>
<tr>
<td><code>FB</code></td>
<td><code>Framebuffer</code>，用于存储单个图层要实现的内容<br>它是一块内存区域，可以理解为一块画布，驱动程序和应用都能访问它。绘画前需要将它格式化，设定绘制的色彩模式（例如<code>RGB888</code>，<code>YUV</code>等）和画布的大小（分辨率）</td>
</tr>
<tr>
<td><code>VBLANK</code></td>
<td>软件和硬件的同步机制，<code>RGB</code>时序中的垂直消影区，软件通常使用硬件<code>VSYNC</code>来实现</td>
</tr>
<tr>
<td><code>property</code></td>
<td>任何你想设置的参数都可以做成<code>property</code>，是<code>DRM</code>驱动中最灵活、最方便的<code>Mode setting</code>机制</td>
</tr>
<tr>
<td><code>DUMB</code></td>
<td>只支持连续物理内存，基于<code>kernel</code>中通用<code>CMA API</code>实现，多用于小分辨率简单场景</td>
</tr>
<tr>
<td><code>PRIME</code></td>
<td>连续、非连续物理内存都支持，基于<code>DMA-BUF</code>机制，可以实现<code>buffer</code>共享，多用于大内存复杂场景</td>
</tr>
<tr>
<td><code>fence</code></td>
<td><code>buffer</code>同步机制，基于内核<code>dma_fence</code>机制实现，用于防止显示内容出现异步问题</td>
</tr>
</tbody></table>
<h4 id="1-3-目录结构"><a href="#1-3-目录结构" class="headerlink" title="1.3 目录结构"></a>1.3 目录结构</h4><p><code>linux</code>内核将<code>DRM</code>驱动相关的代码都放在<code>drivers/gpu/drm</code>目录下，这下面的文件还是比较多的，我们大概了解一下即可；</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">root@zhengyang:/work/sambashare/rk3399/linux-6.3# ls drivers/gpu/drm/ -I &quot;*.o&quot;</span><br><span class="line">amd                         drm_fbdev_generic.c             drm_print.c                logicvc</span><br><span class="line">arm                         drm_fb_dma_helper.c             drm_privacy_screen.c       Makefile</span><br><span class="line">armada                      drm_fb_helper.c                 drm_privacy_screen_x86.c   mcde</span><br><span class="line">aspeed                      drm_file.c                      drm_probe_helper.c         mediatek</span><br><span class="line">ast                         drm_flip_work.c                 drm_property.c             meson</span><br><span class="line">atmel-hlcdc                 drm_format_helper.c             drm_rect.c                 mgag200</span><br><span class="line">bridge                      drm_fourcc.c                    drm_scatter.c              modules.order</span><br><span class="line">built-in.a                  drm_framebuffer.c               drm_self_refresh_helper.c  msm</span><br><span class="line">display                     drm_gem_atomic_helper.c         drm_shmem_helper.ko        mxsfb</span><br><span class="line">drm_agpsupport.c            drm_gem.c                       drm_shmem_helper.mod       nouveau</span><br><span class="line">drm_aperture.c              drm_gem_dma_helper.c            drm_shmem_helper.mod.c     omapdrm</span><br><span class="line">drm_atomic.c                drm_gem_framebuffer_helper.c    drm_simple_kms_helper.c    panel</span><br><span class="line">drm_atomic_helper.c         drm_gem_shmem_helper.c          drm_syncobj.c              panfrost</span><br><span class="line">drm_atomic_state_helper.c   drm_gem_ttm_helper.c            drm_sysfs.c                pl111</span><br><span class="line">drm_atomic_uapi.c           drm_gem_vram_helper.c           drm_trace.h                qxl</span><br><span class="line">drm_auth.c                  drm_hashtab.c                   drm_trace_points.c         radeon</span><br><span class="line">drm_blend.c                 drm_internal.h                  drm_ttm_helper.ko          rcar-du</span><br><span class="line">drm_bridge.c                drm_ioc32.c                     drm_ttm_helper.mod         rockchip</span><br><span class="line">drm_bridge_connector.c      drm_ioctl.c                     drm_ttm_helper.mod.c       scheduler</span><br><span class="line">drm_buddy.c                 drm_irq.c                       drm_vblank.c               shmobile</span><br><span class="line">drm_bufs.c                  drm_kms_helper_common.c         drm_vblank_work.c          solomon</span><br><span class="line">drm_cache.c                 drm_lease.c                     drm_vma_manager.c          sprd</span><br><span class="line">drm_client.c                drm_legacy.h                    drm_vm.c                   sti</span><br><span class="line">drm_client_modeset.c        drm_legacy_misc.c               drm_vram_helper.ko         stm</span><br><span class="line">drm_color_mgmt.c            drm_lock.c                      drm_vram_helper.mod        sun4i</span><br><span class="line">drm_connector.c             drm_managed.c                   drm_vram_helper.mod.c      tegra</span><br><span class="line">drm_context.c               drm_memory.c                    drm_writeback.c            tests</span><br><span class="line">drm_crtc.c                  drm_mipi_dbi.c                  etnaviv                    tidss</span><br><span class="line">drm_crtc_helper.c           drm_mipi_dsi.c                  exynos                     tilcdc</span><br><span class="line">drm_crtc_helper_internal.h  drm_mm.c                        fsl-dcu                    tiny</span><br><span class="line">drm_crtc_internal.h         drm_mode_config.c               gma500                     ttm</span><br><span class="line">drm_damage_helper.c         drm_mode_object.c               gud                        tve200</span><br><span class="line">drm_debugfs.c               drm_modes.c                     hisilicon                  udl</span><br><span class="line">drm_debugfs_crc.c           drm_modeset_helper.c            hyperv                     v3d</span><br><span class="line">drm_displayid.c             drm_modeset_lock.c              i2c                        vboxvideo</span><br><span class="line">drm_dma.c                   drm_of.c                        i915                       vc4</span><br><span class="line">drm_drv.c                   drm_panel.c                     imx                        vgem</span><br><span class="line">drm_dumb_buffers.c          drm_panel_orientation_quirks.c  ingenic                    virtio</span><br><span class="line">drm_edid.c                  drm_pci.c                       Kconfig                    vkms</span><br><span class="line">drm_edid_load.c             drm_plane.c                     kmb                        vmwgfx</span><br><span class="line">drm_encoder.c               drm_plane_helper.c              lib                        xen</span><br><span class="line">drm_encoder_slave.c         drm_prime.c                     lima                       xlnx</span><br></pre></td></tr></table></figure>

<p>其中：</p>
<ul>
<li><p><code>drm_drv.c</code>：<code>DRM core</code>核心实现；</p>
</li>
<li><p><code>drm_gem.c</code>：提供了<code>GEM</code>相关的<code>API</code>；</p>
</li>
</ul>
<p>其中<code>rockchip</code>为<code>Rockchip</code>官方的实现代码：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">root@zhengyang:/work/sambashare/rk3399/linux-6.3# ls drivers/gpu/drm/rockchip/ -I &quot;*.o&quot;</span><br><span class="line">analogix_dp-rockchip.c  inno_hdmi.c         rockchip_drm_drv.h   rockchip_drm_vop.h</span><br><span class="line">built-in.a              inno_hdmi.h         rockchip_drm_fb.c    rockchip_lvds.c</span><br><span class="line">cdn-dp-core.c           Kconfig             rockchip_drm_fb.h    rockchip_lvds.h</span><br><span class="line">cdn-dp-core.h           Makefile            rockchip_drm_gem.c   rockchip_rgb.c</span><br><span class="line">cdn-dp-reg.c            modules.order       rockchip_drm_gem.h   rockchip_rgb.h</span><br><span class="line">cdn-dp-reg.h            rk3066_hdmi.c       rockchip_drm_vop2.c  rockchip_vop2_reg.c</span><br><span class="line">dw_hdmi-rockchip.c      rk3066_hdmi.h       rockchip_drm_vop2.h  rockchip_vop_reg.c</span><br><span class="line">dw-mipi-dsi-rockchip.c  rockchip_drm_drv.c  rockchip_drm_vop.c   rockchip_vop_reg.h</span><br></pre></td></tr></table></figure>

<h3 id="二、硬件抽象"><a href="#二、硬件抽象" class="headerlink" title="二、硬件抽象"></a>二、硬件抽象</h3><p>对于初学者来说，往往让人迷惑的不是<code>DRM</code>中<code>objects</code>的概念，而是如何去建立这些<code>objects</code>与实际硬件的对应关系。因为并不是所有的<code>Display</code>硬件都能很好的对应上<code>plane/crtc/encoder/connector</code>这些<code>objects</code>。</p>
<p>在学如何去抽象显示硬件到具体的<code>RM object</code>之前，我们先普及一下<code>MIPI</code>相关的知识。</p>
<p><code>MIPI(Mobile Industry Processor Interface)</code>是2003年由<code>ARM, Nokia, ST ,TI</code>等公司成立的一个联盟，目的是把手机内部的接口如摄像头、显示屏接口、射频&#x2F;基带接口等标准化，从而减少手机设计的复杂程度和增加设计灵活性。</p>
<p><code>MIPI</code>联盟下面有不同的<code>WorkGroup</code>，分别定义了一系列的手机内部接口标准，比如:</p>
<ul>
<li>摄像头接口<code>CSI（Camera Serial Interface）</code>；</li>
<li>显示接口<code>DSI（Display Serial Interface）</code>；</li>
<li>射频接口<code>DigRF</code>；</li>
<li>麦克风&#x2F;喇叭接口<code>SLIMbus</code>等。</li>
</ul>
<h4 id="2-1-MIPI-DSI-接口"><a href="#2-1-MIPI-DSI-接口" class="headerlink" title="2.1  MIPI DSI 接口"></a>2.1  <code>MIPI DSI</code> 接口</h4><p>下图为一个典型的<code>MIPI DSI</code>接口屏的硬件连接框图：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309091810756.png" width='600px'/>

<p>它在软件架构上与<code>DRM object</code>的对应关系如下图：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202308282320783.png" width='600px'/>

<p>多余的细节不做介绍，这里只说明为何如此分配<code>drm object</code>：</p>
<table>
<thead>
<tr>
<th><strong>object</strong></th>
<th><strong>说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>crtc</code></td>
<td><code>RGB timing</code>的产生，以及显示数据的更新，都需要访问<code>Dislay Controller</code>硬件寄存器，因此放在<code>Display Controller</code>驱动中</td>
</tr>
<tr>
<td><code>plane</code></td>
<td>对<code>Overlay</code>硬件的抽象，同样需要访问<code>Display Controller</code>寄存器，因此也放在<code>Display Controller</code>驱动中</td>
</tr>
<tr>
<td><code>encoder</code></td>
<td>将<code>RGB</code>并行信号转换为<code>DSI</code>行信号，需要配置<code>DSI</code>硬件寄存器，因此放在<code>DSI Controller</code>驱动中</td>
</tr>
<tr>
<td><code>connector</code></td>
<td>可以通过<code>drm_panel</code>来获取<code>LCD</code>的<code>mode</code>信息，但是<code>encoder</code>在哪，<code>connector</code>就在哪，因此放在<code>DSI Controller</code>驱动中</td>
</tr>
<tr>
<td><code>drm_panel</code></td>
<td>用于获取<code>LCD mode</code>参数，并提供<code>LCD</code>休眠唤醒的回调接口，供<code>encoder</code>调用，因此放在<code>LCD</code>驱动中</td>
</tr>
</tbody></table>
<p>驱动参考：<code>https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c</code>。</p>
<p>有关<code>MIPI DSI</code>可以参考<a target="_blank" rel="noopener" href="https://stephenzhou.blog.csdn.net/article/details/12364875"><code>MIPI 系列之 DSI</code></a>。</p>
<h4 id="2-2-MIPI-DPI接口"><a href="#2-2-MIPI-DPI接口" class="headerlink" title="2.2 MIPI DPI接口"></a>2.2 <code>MIPI DPI</code>接口</h4><p><code>DPI</code>接口也就是我们常说的<code>RGB</code>并行接口，<code>Video</code>数据通过<code>RGB</code>并行总线传输，控制命令（如初始化、休眠、唤醒等）则通过<code>SPI/I2C</code> 总线传输，比如早期的<code>S3C2440 SoC</code>平台。下图为一个典型的<code>MIPI DPI</code>接口屏的硬件连接框图：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202308282323537.png" width='600px'/>

<p>该硬件连接在软件架构上与<code>DRM object</code>的对应关系如下图：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202308282323626.png" width='600px'/>

<p>多余的细节不做介绍，这里只说明为何如此分配<code>drm object</code>：</p>
<table>
<thead>
<tr>
<th><strong>object</strong></th>
<th><strong>说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>crtc</code></td>
<td><code>RGB timing</code>的产生，以及显示数据的更新，都需要访问<code>LCD Controller</code>硬件寄存器，因此放在<code>LCD Controller</code>驱动中</td>
</tr>
<tr>
<td><code>plane</code></td>
<td><code>LCDC</code>没有<code>Overlay</code>硬件，它只有一个数据源通道，被抽象为<code>Primary Plane</code>，同样需要访问 <code>LCDC</code>硬件寄存器，因此放在<code>LCDC</code>驱动中</td>
</tr>
<tr>
<td><code>encoder</code></td>
<td>由于<code>DPI</code>接口本身不需要对<code>RGB</code>信号做任何转换，因此没有哪个硬件与之对应。但是<code>drm objects</code>又缺一不可，因此实现了一个虚拟的<code>encoder object</code>。至于为什么要放在<code>LCDC</code>驱动中实现，纯粹只是为了省事而已，你也可以放在一个虚拟的平台驱动中去实现该<code>encoder object</code></td>
</tr>
<tr>
<td><code>connector</code></td>
<td><code>encoder</code>在哪，<code>connector</code>就在哪，没什么好说的了</td>
</tr>
<tr>
<td><code>drm_panel</code></td>
<td>用于获取<code>LCD mode</code>参数，并提供<code>LCD</code>休眠唤醒的回调接口，供<code>encoder</code>调用，因此放在<code>LCD</code>驱动中</td>
</tr>
</tbody></table>
<p>驱动参考：<code>https://elixir.bootlin.com/linux/v5.0/source/drivers/gpu/drm/panel/panel-sitronix-st7789v.c</code>。</p>
<h4 id="2-3-MIPI-DBI接口"><a href="#2-3-MIPI-DBI接口" class="headerlink" title="2.3 MIPI DBI接口"></a>2.3 <code>MIPI DBI</code>接口</h4><p><code>DBI</code>接口也就是我们平时常说的<code>MCU</code>或<code>SPI</code>接口屏，这类屏的<code>VIDEO</code>数据和控制命令都是通过同一总线接口（<code>I80、SPI</code>接口）进行传输，而且这类屏幕必须内置<code>GRAM</code>显存，否则屏幕无法维持正常显示。</p>
<p>下图为一个典型的<code>DBI</code>接口屏的硬件连接框图：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309091810863.png" width='600px'/>

<p>该硬件连接在软件架构上与<code>DRM object</code>的对应关系如下：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202308282326620.png" width='600px'/>

<p>上图参考<code>kernel4.19 tinydrm</code>软件架构。</p>
<table>
<thead>
<tr>
<th><strong>object</strong></th>
<th><strong>说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>crtc</code></td>
<td>这类硬件本身不需要任何<code>RGB timing</code>信号，因此也没有实际的硬件与之对应。但是<code>drm objects</code>缺一不可，需要实现一个虚拟的<code>crtc object</code>。由于更新图像数据的动作需要通过<code>SPI</code>总线发送命令才能完成，因此放在了<code>LCD</code>驱动中</td>
</tr>
<tr>
<td><code>plane</code></td>
<td>没有实际的硬件与之对应，但<code>crtc</code>初始化时需要一个<code>plane object</code>作为参数传递，因此和<code>crtc</code>放在一起</td>
</tr>
<tr>
<td><code>encoder</code></td>
<td>没有实际的硬件与之对应，使用虚拟的<code>encoder object</code>。因为这类硬件并不是将<code>RGB</code>信号转换为<code>SPI</code>信号，而是根本就没有<code>RGB</code>信号源，也就无从谈起<code>encoder</code>设备。但是为了通知<code>LCD</code>休眠唤醒，需要调用<code>LCD</code>驱动的相应接口，因此放在<code>LCD</code>驱动中</td>
</tr>
<tr>
<td><code>connector</code></td>
<td>由于没有了<code>drm_panel</code>，需要调用<code>LCD</code>接口来获取<code>mode</code>参数，因此放在<code>LCD</code>驱动中</td>
</tr>
</tbody></table>
<p>驱动参考：<code>https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/tinydrm/ili9341.c</code>。</p>
<h3 id="三、DRM-Objects"><a href="#三、DRM-Objects" class="headerlink" title="三、DRM Objects"></a>三、<code>DRM Objects</code></h3><p>在编写<code>DRM</code>驱动程序之前，我们先对<code>DRM</code>内部的<code>Objects</code>进行一番介绍，因为这些<code>Objects</code>是<code>DRM</code>框架的核心，它们缺一不可。</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202308282307244.png" width='600px'/>

<p>上图蓝色部分则是对物理硬件的抽象，黄色部分则是对软件的抽象。虚线以上的为<code>drm_mode_object</code>（或者说是<code>modset object</code>），虚线以下为<code>drm_gem_object</code>（或者说是<code>gem objec</code>）。</p>
<p>这些<code>objects</code>之间的关系：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202308282310791.png" width='700px'/>

<p>通过上图可以看到，<code>plane</code>是连接<code>framebuffer</code>和<code>crtc</code>的纽带，而<code>encoder</code>则是连接<code>crtc</code>和<code>connector</code>的纽带。与物理<code>buffer</code>直接打交道的是<code>gem</code>而不是<code>framebuffer</code>。</p>
<p>需要注意的是，上图蓝色部分即使没有实际的硬件与之对应，在软件驱动中也需要实现这些<code>objects</code>，否则<code>DRM</code>子系统无法正常运行。</p>
<h4 id="3-1-modeset-object"><a href="#3-1-modeset-object" class="headerlink" title="3.1  modeset object"></a>3.1  <code>modeset object</code></h4><p>对于<code>plane</code>、<code>crtc</code>、<code>encoder</code>、<code>connector</code>几个对象，它们有一个公共基类<code>struct drm_mode_object</code>，这几个对象都由此基类扩展而来（该类作为<code>crtc</code>等结构体的成员）。事实上这个基类扩展出来的子类并不是只有上面提到的几种，只不过这四种比较常见。其定义在<code>include/drm/drm_mode_object.h</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_mode_object - base structure for modeset objects</span></span><br><span class="line"><span class="comment"> * @id: userspace visible identifier</span></span><br><span class="line"><span class="comment"> * @type: type of the object, one of DRM_MODE_OBJECT\_\*</span></span><br><span class="line"><span class="comment"> * @properties: properties attached to this object, including values</span></span><br><span class="line"><span class="comment"> * @refcount: reference count for objects which with dynamic lifetime</span></span><br><span class="line"><span class="comment"> * @free_cb: free function callback, only set for objects with dynamic lifetime</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Base structure for modeset objects visible to userspace. Objects can be</span></span><br><span class="line"><span class="comment"> * looked up using drm_mode_object_find(). Besides basic uapi interface</span></span><br><span class="line"><span class="comment"> * properties like @id and @type it provides two services:</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * - It tracks attached properties and their values. This is used by &amp;drm_crtc,</span></span><br><span class="line"><span class="comment"> *   &amp;drm_plane and &amp;drm_connector. Properties are attached by calling</span></span><br><span class="line"><span class="comment"> *   drm_object_attach_property() before the object is visible to userspace.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * - For objects with dynamic lifetimes (as indicated by a non-NULL @free_cb) it</span></span><br><span class="line"><span class="comment"> *   provides reference counting through drm_mode_object_get() and</span></span><br><span class="line"><span class="comment"> *   drm_mode_object_put(). This is used by &amp;drm_framebuffer, &amp;drm_connector</span></span><br><span class="line"><span class="comment"> *   and &amp;drm_property_blob. These objects provide specialized reference</span></span><br><span class="line"><span class="comment"> *   counting wrappers.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_object</span> &#123;</span></span><br><span class="line">        <span class="type">uint32_t</span> id;</span><br><span class="line">        <span class="type">uint32_t</span> type;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_object_properties</span> *<span class="title">properties</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">kref</span> <span class="title">refcount</span>;</span></span><br><span class="line">        <span class="type">void</span> (*free_cb)(<span class="keyword">struct</span> kref *kref);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>包括以下成员：</p>
<ul>
<li><p><code>id</code>：用户空间可见的唯一标识标识符，基于<code>idr</code>算法分配得到的；</p>
</li>
<li><p><code>type</code>：对象的类型，可以是<code>DRM_MODE_OBJECT_*</code>中的一个；</p>
</li>
<li><p><code>properties</code>：附加到该对象的属性，包括属性的值；在<code>DRM</code>驱动中，每个对象都可以拥有一组属性（例如分辨率、刷新率等），并且可以动态地增加、删除或修改属性。这些属性可以被用户空间的应用程序或者其他驱动程序获取或者设置；</p>
</li>
<li><p><code>refcount</code>：具有动态生命周期的对象的引用计数；指<code>drm_mode_object</code>对象在内核中的生命周期的管理，每个<code>drm_mode_object</code>对象都有一个引用计数；</p>
<ul>
<li>当一个对象被创建时，它的引用计数被初始化为1；</li>
<li>每当一个新的引用指向该对象时，它的引用计数就会增加1；</li>
<li>每当一个引用被释放时，它的引用计数就会减少1；</li>
<li>当对象的引用计数降为0时，内核会自动释放该对象。</li>
<li>这种方式确保了内核中不会存在不再使用的对象，从而避免了内存泄漏。</li>
</ul>
</li>
<li><p><code>free_cb</code>：释放函数回调，仅对具有动态生命周期的对象设置；</p>
</li>
</ul>
<p>该结构体提供了用户空间可见的<code>modeset objects</code>的基本结构，可以通过<code>drm_mode_object_find</code>函数查找对象。</p>
<p>为了更加清晰的了解<code>struct drm_mode_object</code>、<code>struct drm_object_properties</code>、<code>struct snd_jack_kctl</code>数据结构的关系，我们绘制了如下关系图：</p>
<img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309091810235.svg+xml" width='700px'/>

<h4 id="3-2-对象类型"><a href="#3-2-对象类型" class="headerlink" title="3.2 对象类型"></a>3.2 对象类型</h4><p><code>type</code>主要包含以下几种类型，定义在<code>include/uapi/drm/drm_mode.h</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_CRTC 0xcccccccc</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_MODE 0xdededede</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_FB 0xfbfbfbfb</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_BLOB 0xbbbbbbbb</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_PLANE 0xeeeeeeee</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_MODE_OBJECT_ANY 0</span></span><br></pre></td></tr></table></figure>

<h4 id="3-3-对象属性"><a href="#3-3-对象属性" class="headerlink" title="3.3 对象属性"></a>3.3 对象属性</h4><p><code>struct drm_object_properties</code>用于描述对象的属性，定义在<code>include/drm/drm_mode_object.h</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_object_properties - property tracking for &amp;drm_mode_object</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_object_properties</span> &#123;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @count: number of valid properties, must be less than or equal to</span></span><br><span class="line"><span class="comment">         * DRM_OBJECT_MAX_PROPERTY.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> count;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @properties: Array of pointers to &amp;drm_property.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * <span class="doctag">NOTE:</span> if we ever start dynamically destroying properties (ie.</span></span><br><span class="line"><span class="comment">         * not at drm_mode_config_cleanup() time), then we&#x27;d have to do</span></span><br><span class="line"><span class="comment">         * a better job of detaching property from mode objects to avoid</span></span><br><span class="line"><span class="comment">         * dangling property pointers:</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span> *<span class="title">properties</span>[<span class="title">DRM_OBJECT_MAX_PROPERTY</span>];</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @values: Array to store the property values, matching @properties. Do</span></span><br><span class="line"><span class="comment">         * not read/write values directly, but use</span></span><br><span class="line"><span class="comment">         * drm_object_property_get_value() and drm_object_property_set_value().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Note that atomic drivers do not store mutable properties in this</span></span><br><span class="line"><span class="comment">         * array, but only the decoded values in the corresponding state</span></span><br><span class="line"><span class="comment">         * structure. The decoding is done using the &amp;drm_crtc.atomic_get_property and</span></span><br><span class="line"><span class="comment">         * &amp;drm_crtc.atomic_set_property hooks for &amp;struct drm_crtc. For</span></span><br><span class="line"><span class="comment">         * &amp;struct drm_plane the hooks are &amp;drm_plane_funcs.atomic_get_property and</span></span><br><span class="line"><span class="comment">         * &amp;drm_plane_funcs.atomic_set_property. And for &amp;struct drm_connector</span></span><br><span class="line"><span class="comment">         * the hooks are &amp;drm_connector_funcs.atomic_get_property and</span></span><br><span class="line"><span class="comment">         * &amp;drm_connector_funcs.atomic_set_property .</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Hence atomic drivers should not use drm_object_property_set_value()</span></span><br><span class="line"><span class="comment">         * and drm_object_property_get_value() on mutable objects, i.e. those</span></span><br><span class="line"><span class="comment">         * without the DRM_MODE_PROP_IMMUTABLE flag set.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * For atomic drivers the default value of properties is stored in this</span></span><br><span class="line"><span class="comment">         * array, so drm_object_property_get_default_value can be used to</span></span><br><span class="line"><span class="comment">         * retrieve it.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">uint64_t</span> values[DRM_OBJECT_MAX_PROPERTY];</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>该结构体包含以下字段：</p>
<ul>
<li><code>count</code>：<code>properties</code>数组长度，必须小于或等于<code>DRM_OBJECT_MAX_PROPERTY</code>（值为24）；</li>
<li><code>properties</code>：指向<code>drm_property</code>的指针数组；</li>
<li><code>values</code>：用于存储属性值的数组，与<code>properties</code>匹配；</li>
</ul>
<p>其中<code>struct drm_property</code>定义在<code>include/drm/drm_property.h</code>:</p>
<details>
<summary>
  点击查看代码
</summary>


<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_property - modeset object property</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure represent a modeset object property. It combines both the name</span></span><br><span class="line"><span class="comment"> * of the property with the set of permissible values. This means that when a</span></span><br><span class="line"><span class="comment"> * driver wants to use a property with the same name on different objects, but</span></span><br><span class="line"><span class="comment"> * with different value ranges, then it must create property for each one. An</span></span><br><span class="line"><span class="comment"> * example would be rotation of &amp;drm_plane, when e.g. the primary plane cannot</span></span><br><span class="line"><span class="comment"> * be rotated. But if both the name and the value range match, then the same</span></span><br><span class="line"><span class="comment"> * property structure can be instantiated multiple times for the same object.</span></span><br><span class="line"><span class="comment"> * Userspace must be able to cope with this and cannot assume that the same</span></span><br><span class="line"><span class="comment"> * symbolic property will have the same modeset object ID on all modeset</span></span><br><span class="line"><span class="comment"> * objects.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Properties are created by one of the special functions, as explained in</span></span><br><span class="line"><span class="comment"> * detail in the @flags structure member.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * To actually expose a property it must be attached to each object using</span></span><br><span class="line"><span class="comment"> * drm_object_attach_property(). Currently properties can only be attached to</span></span><br><span class="line"><span class="comment"> * &amp;drm_connector, &amp;drm_crtc and &amp;drm_plane.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Properties are also used as the generic metadatatransport for the atomic</span></span><br><span class="line"><span class="comment"> * IOCTL. Everything that was set directly in structures in the legacy modeset</span></span><br><span class="line"><span class="comment"> * IOCTLs (like the plane source or destination windows, or e.g. the links to</span></span><br><span class="line"><span class="comment"> * the CRTC) is exposed as a property with the DRM_MODE_PROP_ATOMIC flag set.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span> &#123;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @head: per-device list of properties, for cleanup.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">head</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @base: base KMS object</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_object</span> <span class="title">base</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @flags:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Property flags and type. A property needs to be one of the following</span></span><br><span class="line"><span class="comment">         * types:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_RANGE</span></span><br><span class="line"><span class="comment">         *     Range properties report their minimum and maximum admissible unsigned values.</span></span><br><span class="line"><span class="comment">         *     The KMS core verifies that values set by application fit in that</span></span><br><span class="line"><span class="comment">         *     range. The range is unsigned. Range properties are created using</span></span><br><span class="line"><span class="comment">         *     drm_property_create_range().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_SIGNED_RANGE</span></span><br><span class="line"><span class="comment">         *     Range properties report their minimum and maximum admissible unsigned values.</span></span><br><span class="line"><span class="comment">         *     The KMS core verifies that values set by application fit in that</span></span><br><span class="line"><span class="comment">         *     range. The range is signed. Range properties are created using</span></span><br><span class="line"><span class="comment">         *     drm_property_create_signed_range().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_ENUM</span></span><br><span class="line"><span class="comment">         *     Enumerated properties take a numerical value that ranges from 0 to</span></span><br><span class="line"><span class="comment">         *     the number of enumerated values defined by the property minus one,</span></span><br><span class="line"><span class="comment">         *     and associate a free-formed string name to each value. Applications</span></span><br><span class="line"><span class="comment">         *     can retrieve the list of defined value-name pairs and use the</span></span><br><span class="line"><span class="comment">         *     numerical value to get and set property instance values. Enum</span></span><br><span class="line"><span class="comment">         *     properties are created using drm_property_create_enum().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_BITMASK</span></span><br><span class="line"><span class="comment">         *     Bitmask properties are enumeration properties that additionally</span></span><br><span class="line"><span class="comment">         *     restrict all enumerated values to the 0..63 range. Bitmask property</span></span><br><span class="line"><span class="comment">         *     instance values combine one or more of the enumerated bits defined</span></span><br><span class="line"><span class="comment">         *     by the property. Bitmask properties are created using</span></span><br><span class="line"><span class="comment">         *     drm_property_create_bitmask().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_OBJECT</span></span><br><span class="line"><span class="comment">         *     Object properties are used to link modeset objects. This is used</span></span><br><span class="line"><span class="comment">         *     extensively in the atomic support to create the display pipeline,</span></span><br><span class="line"><span class="comment">         *     by linking &amp;drm_framebuffer to &amp;drm_plane, &amp;drm_plane to</span></span><br><span class="line"><span class="comment">         *     &amp;drm_crtc and &amp;drm_connector to &amp;drm_crtc. An object property can</span></span><br><span class="line"><span class="comment">         *     only link to a specific type of &amp;drm_mode_object, this limit is</span></span><br><span class="line"><span class="comment">         *     enforced by the core. Object properties are created using</span></span><br><span class="line"><span class="comment">         *     drm_property_create_object().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *     Object properties work like blob properties, but in a more</span></span><br><span class="line"><span class="comment">         *     general fashion. They are limited to atomic drivers and must have</span></span><br><span class="line"><span class="comment">         *     the DRM_MODE_PROP_ATOMIC flag set.</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_BLOB</span></span><br><span class="line"><span class="comment">         *     Blob properties store a binary blob without any format restriction.</span></span><br><span class="line"><span class="comment">         *     The binary blobs are created as KMS standalone objects, and blob</span></span><br><span class="line"><span class="comment">         *     property instance values store the ID of their associated blob</span></span><br><span class="line"><span class="comment">         *     object. Blob properties are created by calling</span></span><br><span class="line"><span class="comment">         *     drm_property_create() with DRM_MODE_PROP_BLOB as the type.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *     Actual blob objects to contain blob data are created using</span></span><br><span class="line"><span class="comment">         *     drm_property_create_blob(), or through the corresponding IOCTL.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *     Besides the built-in limit to only accept blob objects blob</span></span><br><span class="line"><span class="comment">         *     properties work exactly like object properties. The only reasons</span></span><br><span class="line"><span class="comment">         *     blob properties exist is backwards compatibility with existing</span></span><br><span class="line"><span class="comment">         *     userspace.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * In addition a property can have any combination of the below flags:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_ATOMIC</span></span><br><span class="line"><span class="comment">         *     Set for properties which encode atomic modeset state. Such</span></span><br><span class="line"><span class="comment">         *     properties are not exposed to legacy userspace.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM_MODE_PROP_IMMUTABLE</span></span><br><span class="line"><span class="comment">         *     Set for properties whose values cannot be changed by</span></span><br><span class="line"><span class="comment">         *     userspace. The kernel is allowed to update the value of these</span></span><br><span class="line"><span class="comment">         *     properties. This is generally used to expose probe state to</span></span><br><span class="line"><span class="comment">         *     userspace, e.g. the EDID, or the connector path property on DP</span></span><br><span class="line"><span class="comment">         *     MST sinks. Kernel can update the value of an immutable property</span></span><br><span class="line"><span class="comment">         *     by calling drm_object_property_set_value().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">uint32_t</span> flags;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @name: symbolic name of the properties</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">char</span> name[DRM_PROP_NAME_LEN];</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @num_values: size of the @values array.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">uint32_t</span> num_values;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @values:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Array with limits and values for the property. The</span></span><br><span class="line"><span class="comment">         * interpretation of these limits is dependent upon the type per @flags.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">uint64_t</span> *values;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dev: DRM device</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @enum_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of &amp;drm_prop_enum_list structures with the symbolic names for</span></span><br><span class="line"><span class="comment">         * enum and bitmask values.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">enum_list</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

</details>

<h4 id="3-4-gem-object"><a href="#3-4-gem-object" class="headerlink" title="3.4 gem object"></a>3.4 <code>gem object</code></h4><p><code>GEM</code>主要负责显示<code>buffer</code>的分配和释放，<code>linux</code>内核中使用<code>struct drm_gem_object</code>表示<code>GEM</code>对象，驱动一般需要用私有信息来扩展<code>GEM</code>对象，因此<code>struct drm_gem_object</code>都是嵌入在驱动自定义的<code>GEM</code>结构体内的。<br><code>gem object</code>的创建以及初始化步骤如下：</p>
<ul>
<li>创建一个<code>GEM</code>对象，驱动为自定义<code>GEM</code>对象申请内存；</li>
<li>通过<code>drm_gem_object_init</code>来初始化嵌入在其中的<code>struct drm_gem_object</code>；</li>
<li>通过<code>drm_gem_handle_create</code>创建<code>GEM</code>对象<code>handle</code>；</li>
<li>分配物理<code>buffer</code>；</li>
<li>通过<code>mmap</code>将物理<code>buffer</code>映射到用户空间；这样用户空间就可以直接访问了；</li>
</ul>
<p><code>struct drm_gem_object</code>定义在<code>include/drm/drm_gem.h</code>:</p>
<details>
<summary>点击查看代码</summary>


<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_gem_object - GEM buffer object</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure defines the generic parts for GEM buffer objects, which are</span></span><br><span class="line"><span class="comment"> * mostly around handling mmap and userspace handles.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Buffer objects are often abbreviated to BO.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> &#123;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @refcount:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Reference count of this object</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Please use drm_gem_object_get() to acquire and drm_gem_object_put_locked()</span></span><br><span class="line"><span class="comment">         * or drm_gem_object_put() to release a reference to a GEM</span></span><br><span class="line"><span class="comment">         * buffer object.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">kref</span> <span class="title">refcount</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @handle_count:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is the GEM file_priv handle count of this object.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Each handle also holds a reference. Note that when the handle_count</span></span><br><span class="line"><span class="comment">         * drops to 0 any global names (e.g. the id in the flink namespace) will</span></span><br><span class="line"><span class="comment">         * be cleared.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Protected by &amp;drm_device.object_name_lock.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">unsigned</span> handle_count;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dev: DRM dev this object belongs to.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @filp:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * SHMEM file node used as backing storage for swappable buffer objects.</span></span><br><span class="line"><span class="comment">         * GEM also supports driver private objects with driver-specific backing</span></span><br><span class="line"><span class="comment">         * storage (contiguous DMA memory, special reserved blocks). In this</span></span><br><span class="line"><span class="comment">         * case @filp is NULL.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">filp</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @vma_node:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Mapping info for this object to support mmap. Drivers are supposed to</span></span><br><span class="line"><span class="comment">         * allocate the mmap offset using drm_gem_create_mmap_offset(). The</span></span><br><span class="line"><span class="comment">         * offset itself can be retrieved using drm_vma_node_offset_addr().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Memory mapping itself is handled by drm_gem_mmap(), which also checks</span></span><br><span class="line"><span class="comment">         * that userspace is allowed to access the object.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_vma_offset_node</span> <span class="title">vma_node</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @size:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Size of the object, in bytes.  Immutable over the object&#x27;s</span></span><br><span class="line"><span class="comment">         * lifetime.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">size_t</span> size;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @name:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Global name for this object, starts at 1. 0 means unnamed.</span></span><br><span class="line"><span class="comment">         * Access is covered by &amp;drm_device.object_name_lock. This is used by</span></span><br><span class="line"><span class="comment">         * the GEM_FLINK and GEM_OPEN ioctls.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> name;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dma_buf:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * dma-buf associated with this GEM object.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Pointer to the dma-buf associated with this gem object (either</span></span><br><span class="line"><span class="comment">         * through importing or exporting). We break the resulting reference</span></span><br><span class="line"><span class="comment">         * loop when the last gem handle for this object is released.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Protected by &amp;drm_device.object_name_lock.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">dma_buf</span> *<span class="title">dma_buf</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @import_attach:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * dma-buf attachment backing this object.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Any foreign dma_buf imported as a gem object has this set to the</span></span><br><span class="line"><span class="comment">         * attachment point for the device. This is invariant over the lifetime</span></span><br><span class="line"><span class="comment">         * of a gem object.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The &amp;drm_gem_object_funcs.free callback is responsible for</span></span><br><span class="line"><span class="comment">         * cleaning up the dma_buf attachment and references acquired at import</span></span><br><span class="line"><span class="comment">         * time.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Note that the drm gem/prime core does not depend upon drivers setting</span></span><br><span class="line"><span class="comment">         * this field any more. So for drivers where this doesn&#x27;t make sense</span></span><br><span class="line"><span class="comment">         * (e.g. virtual devices or a displaylink behind an usb bus) they can</span></span><br><span class="line"><span class="comment">         * simply leave it as NULL.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">dma_buf_attachment</span> *<span class="title">import_attach</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @resv:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Pointer to reservation object associated with the this GEM object.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Normally (@resv == &amp;@_resv) except for imported GEM objects.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">dma_resv</span> *<span class="title">resv</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @_resv:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * A reservation object for this GEM object.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is unused for imported GEM objects.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">dma_resv</span> _<span class="title">resv</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @funcs:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Optional GEM object functions. If this is set, it will be used instead of the</span></span><br><span class="line"><span class="comment">         * corresponding &amp;drm_driver GEM callbacks.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * New drivers should use this.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object_funcs</span> *<span class="title">funcs</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @lru_node:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List node in a &amp;drm_gem_lru.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">lru_node</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @lru:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The current LRU list that the GEM object is on.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_lru</span> *<span class="title">lru</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

</details>

<p>其中:</p>
<ul>
<li><code>refcount</code>：表示对象引用计数，用于对<code>GEM</code>对象全生命周期的管理；</li>
<li><code>handle_count</code>：表示该对象的句柄计数。每个句柄还持有一个引用，当<code>handle_count</code>降为0时，任何全局名称（例如<code>flink</code>命名空间中的<code>id</code>）都将被清除；</li>
<li><code>dev</code>：该对象所属的<code>DRM</code>设备的指针；</li>
<li><code>filp</code>：用作可互换的缓存对象的后备存储的共享内存文件节点；</li>
<li><code>vma_node</code>：用于支持内存映射的对象的映射信息；</li>
<li><code>size</code>：对象的大小，以字节为单位；</li>
<li><code>name</code>：该对象的全局名称，从1开始。值为0表示无名称；</li>
<li><code>dma_buf</code>：与此<code>GEM</code>对象关联的<code>dma-buf</code>；</li>
<li><code>import_attach</code>：支持此对象的<code>dma-buf</code>附件；</li>
<li><code>resv</code>：与此<code>GEM</code>对象关联的保留对象的指针；</li>
<li><code>_resv</code>：此<code>GEM</code>对象的保留对象；</li>
<li><code>funcs</code>：可选的<code>GEM</code>对象函数。如果设置了此字段，则将使用它而不是对应的<code>drm_driver GEM</code>回调函数；</li>
<li><code>lru_node</code>：在<code>drm_gem_lru</code>中的列表节点；</li>
<li><code>lru</code>：<code>GEM</code>对象当前所在的<code>LRU</code>列表；</li>
</ul>
<h5 id="3-4-1-drm-gem-object-init"><a href="#3-4-1-drm-gem-object-init" class="headerlink" title="3.4.1 drm_gem_object_init"></a>3.4.1 <code>drm_gem_object_init</code></h5><p><code>GEM</code>使用<code>shmem</code>来申请匿名页内存，<code>drm_gem_object_init</code>将会根据传入的<code>size</code>创建一个指定大小的指定大小的<code>shmfs</code>，并将这个<code>shmfs file</code>保存到<code>struct drm_gem_object</code>的<code>filp</code>字段。</p>
<p>当图形硬件使用系统内存，这些内存就会作为对象的主存储直接使用，否则就会作为后备内存。</p>
<p>驱动负责调用<code>shmem_read_mapping_page_gfp</code>做实际物理页面的申请，初始化<code>GEM</code>对象时驱动可以决定申请页面，或者延迟到需要内存时再申请（需要内存时是指：用户态访问内存发生缺页中断，或是驱动需要启动<code>DMA</code>用到这段内存）。</p>
<p>在某些情况下，匿名可分页内存分配并不理想，特别是当硬件要求物理连续的系统内存时，这在嵌入式设备中经常发生。在这种情况下，驱动程序可以通过调用<code>drm_gem_private_object_init</code>来初始化<code>GEM</code>对象，而不是使用<code>drm_gem_object_init</code>，从而创建没有<code>shmfs</code>支持的私有<code>GEM</code>对象。</p>
<p><code>drm_gem_object_init</code>函数定义在<code>drivers/gpu/drm/drm_gem.c</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_gem_object_init - initialize an allocated shmem-backed GEM object</span></span><br><span class="line"><span class="comment"> * @dev: drm_device the object should be initialized for</span></span><br><span class="line"><span class="comment"> * @obj: drm_gem_object to initialize</span></span><br><span class="line"><span class="comment"> * @size: object size 对象的大小</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Initialize an already allocated GEM object of the specified size with</span></span><br><span class="line"><span class="comment"> * shmfs backing store.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drm_gem_object_init</span><span class="params">(<span class="keyword">struct</span> drm_device *dev,</span></span><br><span class="line"><span class="params">                        <span class="keyword">struct</span> drm_gem_object *obj, <span class="type">size_t</span> )</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">filp</span>;</span></span><br><span class="line"></span><br><span class="line">        drm_gem_private_object_init(dev, obj, size);</span><br><span class="line"> </span><br><span class="line">        filp = shmem_file_setup(<span class="string">&quot;drm mm object&quot;</span>, size, VM_NORESERVE);</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(filp))</span><br><span class="line">                <span class="keyword">return</span> PTR_ERR(filp);</span><br><span class="line"></span><br><span class="line">        obj-&gt;filp = filp;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>函数通过调用 <code>drm_gem_private_object_init</code> 进行对象初始化;</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_gem_private_object_init - initialize an allocated private GEM object</span></span><br><span class="line"><span class="comment"> * @dev: drm_device the object should be initialized for</span></span><br><span class="line"><span class="comment"> * @obj: drm_gem_object to initialize</span></span><br><span class="line"><span class="comment"> * @size: object size</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Initialize an already allocated GEM object of the specified size with</span></span><br><span class="line"><span class="comment"> * no GEM provided backing store. Instead the caller is responsible for</span></span><br><span class="line"><span class="comment"> * backing the object and handling it.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">drm_gem_private_object_init</span><span class="params">(<span class="keyword">struct</span> drm_device *dev,</span></span><br><span class="line"><span class="params">                                 <span class="keyword">struct</span> drm_gem_object *obj, <span class="type">size_t</span> size)</span></span><br><span class="line">&#123;</span><br><span class="line">        BUG_ON((size &amp; (PAGE_SIZE - <span class="number">1</span>)) != <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化成员</span></span><br><span class="line">        obj-&gt;dev = dev;</span><br><span class="line">        obj-&gt;filp = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化对象引用计数为1</span></span><br><span class="line">        kref_init(&amp;obj-&gt;refcount);</span><br><span class="line">        obj-&gt;handle_count = <span class="number">0</span>;</span><br><span class="line">        obj-&gt;size = size;</span><br><span class="line">        dma_resv_init(&amp;obj-&gt;_resv);</span><br><span class="line">        <span class="keyword">if</span> (!obj-&gt;resv)</span><br><span class="line">                obj-&gt;resv = &amp;obj-&gt;_resv;</span><br><span class="line"></span><br><span class="line">        drm_vma_node_reset(&amp;obj-&gt;vma_node);</span><br><span class="line">        INIT_LIST_HEAD(&amp;obj-&gt;lru_node);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后通过调用 <code>shmem_file_setup</code> 创建一个与该 <code>GEM</code>对象关联的<code>shmem</code>文件，并将文件指针赋值给 <code>obj-&gt;filp</code>。</p>
<h5 id="3-4-2-GEM对象命名"><a href="#3-4-2-GEM对象命名" class="headerlink" title="3.4.2 GEM对象命名"></a>3.4.2 <code>GEM</code>对象命名</h5><p>用户空间与内核之间的通信使用本地句柄（<code>handle</code>）、全局名称或者文件描述符来引用<code>GEM</code>对象，所有这些都是<code>32bit</code>数。</p>
<p>（1）<code>GEM handle</code>只在特定的<code>DRM</code>文件中有效，应用程序通过驱动程序特定的<code>ioctl</code>获取<code>GEM</code>对象的<code>handle</code>，并可以在其他标准或驱动程序特定的<code>ioctl</code>中使用该<code>handle</code>引用<code>GEM</code>对象，关闭一个<code>DRM</code>文件句柄会释放其中所有的<code>GEM</code>，并解引用相关的<code>GEM</code>对象。</p>
<p>对于<code>GEM handle</code>，函数<code>drm_gem_handle_create</code>用于创建<code>GEM</code>对象的<code>handle</code>，这个函数接收三个参数：</p>
<ul>
<li><code>file_priv</code>：<code>DRM file</code>的私有数据；</li>
<li><code>obj</code>：<code>GEM</code>对象；</li>
<li><code>handlep</code>：将创建的<code>handle</code>返回给调用者的指针<code>handlep</code>；</li>
</ul>
<p><code>drm_gem_handle_create</code>函数定义在<code>drivers/gpu/drm/drm_gem.c</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_gem_handle_create_tail - internal functions to create a handle</span></span><br><span class="line"><span class="comment"> * @file_priv: drm file-private structure to register the handle for</span></span><br><span class="line"><span class="comment"> * @obj: object to register</span></span><br><span class="line"><span class="comment"> * @handlep: pointer to return the created handle to the caller</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This expects the &amp;drm_device.object_name_lock to be held already and will</span></span><br><span class="line"><span class="comment"> * drop it before returning. Used to avoid races in establishing new handles</span></span><br><span class="line"><span class="comment"> * when importing an object from either an flink name or a dma-buf.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Handles must be release again through drm_gem_handle_delete(). This is done</span></span><br><span class="line"><span class="comment"> * when userspace closes @file_priv for all attached handles, or through the</span></span><br><span class="line"><span class="comment"> * GEM_CLOSE ioctl for individual handles.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span></span><br><span class="line"><span class="title function_">drm_gem_handle_create_tail</span><span class="params">(<span class="keyword">struct</span> drm_file *file_priv,</span></span><br><span class="line"><span class="params">                           <span class="keyword">struct</span> drm_gem_object *obj,</span></span><br><span class="line"><span class="params">                           u32 *handlep)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span> =</span> obj-&gt;dev;</span><br><span class="line">        u32 handle;</span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        WARN_ON(!mutex_is_locked(&amp;dev-&gt;object_name_lock));</span><br><span class="line">        <span class="keyword">if</span> (obj-&gt;handle_count++ == <span class="number">0</span>)</span><br><span class="line">                drm_gem_object_get(obj);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * Get the user-visible handle using idr.  Preload and perform</span></span><br><span class="line"><span class="comment">         * allocation under our spinlock.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        idr_preload(GFP_KERNEL);</span><br><span class="line">		<span class="comment">// 获取自旋锁</span></span><br><span class="line">        spin_lock(&amp;file_priv-&gt;table_lock);   </span><br><span class="line"></span><br><span class="line">		<span class="comment">// 基于基数树分配一个唯一的id</span></span><br><span class="line">        ret = idr_alloc(&amp;file_priv-&gt;object_idr, obj, <span class="number">1</span>, <span class="number">0</span>, GFP_NOWAIT); </span><br><span class="line"></span><br><span class="line">		<span class="comment">// 释放自旋锁</span></span><br><span class="line">        spin_unlock(&amp;file_priv-&gt;table_lock);   </span><br><span class="line">        idr_preload_end();</span><br><span class="line"></span><br><span class="line">        mutex_unlock(&amp;dev-&gt;object_name_lock);</span><br><span class="line">        <span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">goto</span> err_unref;</span><br><span class="line"></span><br><span class="line">        handle = ret;</span><br><span class="line"></span><br><span class="line">        ret = drm_vma_node_allow(&amp;obj-&gt;vma_node, file_priv);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_remove;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (obj-&gt;funcs-&gt;open) &#123;</span><br><span class="line">				<span class="comment">// 回调open函数</span></span><br><span class="line">                ret = obj-&gt;funcs-&gt;open(obj, file_priv);</span><br><span class="line">                <span class="keyword">if</span> (ret)</span><br><span class="line">                        <span class="keyword">goto</span> err_revoke;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        *handlep = handle; <span class="comment">// 写回</span></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_revoke:</span><br><span class="line">        drm_vma_node_revoke(&amp;obj-&gt;vma_node, file_priv);</span><br><span class="line">err_remove:</span><br><span class="line">        spin_lock(&amp;file_priv-&gt;table_lock);</span><br><span class="line">        idr_remove(&amp;file_priv-&gt;object_idr, handle);</span><br><span class="line">        spin_unlock(&amp;file_priv-&gt;table_lock);</span><br><span class="line">err_unref:</span><br><span class="line">        drm_gem_object_handle_put_unlocked(obj);</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_gem_handle_create - create a gem handle for an object</span></span><br><span class="line"><span class="comment"> * @file_priv: drm file-private structure to register the handle for</span></span><br><span class="line"><span class="comment"> * @obj: object to register</span></span><br><span class="line"><span class="comment"> * @handlep: pointer to return the created handle to the caller</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Create a handle for this object. This adds a handle reference to the object,</span></span><br><span class="line"><span class="comment"> * which includes a regular reference count. Callers will likely want to</span></span><br><span class="line"><span class="comment"> * dereference the object afterwards.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Since this publishes @obj to userspace it must be fully set up by this point,</span></span><br><span class="line"><span class="comment"> * drivers must call this last in their buffer object creation callbacks.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drm_gem_handle_create</span><span class="params">(<span class="keyword">struct</span> drm_file *file_priv,</span></span><br><span class="line"><span class="params">                          <span class="keyword">struct</span> drm_gem_object *obj,</span></span><br><span class="line"><span class="params">                          u32 *handlep)</span></span><br><span class="line">&#123;</span><br><span class="line">        mutex_lock(&amp;obj-&gt;dev-&gt;object_name_lock);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> drm_gem_handle_create_tail(file_priv, obj, handlep);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以由<code>drm_gem_object_lookup</code>检索与<code>handle</code>关联的<code>GEM</code>对象。</p>
<p>当<code>handle</code>不再需要时，驱动程序使用<code>drm_gem_handle_delete</code>进行删除。释放句柄并不直接销毁或释放<code>GEM</code>对象本身，它只是解除了句柄与<code>GEM</code>对象之间的关联。</p>
<p>为了避免泄漏<code>GEM</code>对象，驱动程序必须确保适当地丢弃自己所拥有的引用（比如在对象创建时获取的初始引用），而不需要特别考虑<code>handle</code>。例如，在实现<code>dumb_create</code>操作时，驱动程序必须在返回<code>handle</code>之前丢弃对<code>GEM</code>对象的初始引用。</p>
<p>(2) <code>GEM</code>名称类似于句柄，但不仅限于<code>DRM</code>文件。它们可以在进程之间传递，用于全局引用<code>GEM</code>对象。应用程序需要通过ioctl的<code>DRM_IOCTL_GEM_FLINK</code>和<code>DRM_IOCTL_GEM_OPEN</code>来将句柄转换为名称，以及将名称转换为句柄。这个转换由<code>DRM core</code>处理，不需要任何驱动程序特定的支持。</p>
<p>(3) <code>GEM</code>也支持通过<code>PRIME dma-buf</code>文件描述符的缓存共享，基于<code>GEM</code>的驱动必须使用提供的辅助函数来实现<code>exoprting</code>和<code>importing</code>。共享文件描述符比可以被猜测的全局名称更安全，因此是首选的缓存共享机制。通过<code>GEM</code>全局名称进行缓存共享仅在传统用户态支持，更进一步的说，<code>PRIME</code>由于其基于<code>dma-buf</code>，还允许跨设备缓存共享。</p>
<h5 id="3-4-3-GEM对象的生命周期"><a href="#3-4-3-GEM对象的生命周期" class="headerlink" title="3.4.3 GEM对象的生命周期"></a>3.4.3 <code>GEM</code>对象的生命周期</h5><p>所有的<code>GEM</code>对象都由<code>GEM Core</code>进行引用计数管理，在<code>DRM</code>子系统中，可以通过调用函数<code>drm_gem_object_get</code>和<code>drm_gem_object_put</code>来获取和释放对<code>GEM</code>对象的引用。</p>
<p>执行<code>drm_gem_object_get</code>调用者必须持有<code>struct drm_device</code>的<code>struct_mutex</code>锁，而为了方便也提供了<code>drm_gem_object_put_unlocked</code>也可以不持锁操作。</p>
<p>当最后一个对<code>GEM</code>对象的引用释放时，<code>GEM core</code>调用<code>struct drm_gem_object_funcs</code>中的<code>free</code>操作，这一操作对于使能了<code>GEM</code>的驱动来说是必须，并且必须释放<code>GEM</code>对象和所有相关资源。</p>
<p>在<code>struct drm_gem_object_funcs</code>中，<code>void (*free)(struct drm_gem_object *obj)</code>函数指针是用于释放GEM对象及其相关资源的操作。驱动程序需要实现这个函数，并在适当的时候调用<code>drm_gem_object_release</code>释放与<code>GEM</code>对象相关的资源。</p>
<h5 id="3-4-4-GEM对象内存映射"><a href="#3-4-4-GEM对象内存映射" class="headerlink" title="3.4.4 GEM对象内存映射"></a>3.4.4 <code>GEM</code>对象内存映射</h5><p>在<code>linux kernel</code>驱动中，实现<code>mmap</code>系统调用离不开两个关键步骤：</p>
<ul>
<li>物理内存的分配;</li>
<li>建立物理内存到用户空间的映射关系。</li>
</ul>
<p>这刚好对应了<code>DRM</code>中的<code>dumb_create</code>和<code>mmap</code>操作，先说映射关系，在<code>linux</code>驱动中建立映射关系的方法主要有如下两种：</p>
<ul>
<li>一次性映射：在<code>mmap</code>回调函数中，一次性建立好整块内存的映射关系，通常以<code>remap_pfn_range</code>为代表；</li>
<li><code>Page Fault</code>：在<code>mmap</code>先不建立映射关系，等上层触发缺页异常时，在<code>fault</code>中断处理函数中建立映射关系，缺哪块补哪块，通常以<code>vm_insert_page</code>为代表。</li>
</ul>
<p>想再进一步学习<code>mmap</code>系统调用的相关知识，推荐大家阅读<a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/article/details/107592704">《<code>DRM</code> 驱动<code>mmap</code>详解：（一）预备知识》</a>和<a target="_blank" rel="noopener" href="https://www.cnblogs.com/huxiao-tee/p/4660352.html">《认真分析<code>mmap</code>：是什么 为什么 怎么用》</a>。</p>
<p>在<code>DRM</code>中，<code>GEM</code>更倾向于通过特定于驱动程序的<code>ioctl</code>实现类似读&#x2F;写的访问<code>buffer</code>，而不是将<code>buffer</code>映射到用户空间。然而，当需要对<code>buffer</code>进行随机访问时（例如执行软件渲染），直接访问对象可能更有效率。</p>
<p>不能直接使用<code>mmap</code>系统调用来映射<code>GEM</code>对象，因为它们没有自己的文件句柄。目前有两种共存的方法将<code>GEM</code>对象映射到用户空间：</p>
<p>(1) 第一种方法使用特定于驱动程序的<code>ioctl</code>来执行映射操作，底层调用<code>do_mmap</code>，这种方法经常被认为不可靠，在新的<code>GEM</code>驱动程序中似乎不被鼓励使用，因此这里不会描述它；</p>
<p>(2) 使用<code>mmap</code>系统调用对<code>DRM</code>文件句柄进行映射；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> *<span class="title function_">mmap</span><span class="params">(<span class="type">void</span> *addr, <span class="type">size_t</span> length, <span class="type">int</span> prot, <span class="type">int</span> flags, <span class="type">int</span> fd, <span class="type">off_t</span> offset)</span></span><br></pre></td></tr></table></figure>

<p><code>DRM</code>通过传递一个虚拟偏移量来标识要映射的<code>GEM</code>对象，该偏移量通过<code>mmap</code>的<code>offset</code>参数传递。在映射之前，<code>GEM</code>对象必须与虚拟偏移量关联起来。为此，驱动程序必须在对象上调用<code>drm_gem_create_mmap_offset</code>。</p>
<p>分配了虚拟偏移量值后，驱动程序必须以特定于驱动程序的方式将该值传递给应用程序，然后可以将其用作<code>mmap</code>的<code>offset</code>参数。</p>
<p><code>GEM</code>核心提供了一个辅助方法<code>drm_gem_mmap</code>来处理对象映射。该方法可以直接设置为<code>mmap</code>文件操作处理程序,它将根据偏移值查找<code>GEM</code>对象，并将<code>VMA</code>操作设置为<code>struct drm_driver gem_vm_ops</code>字段。</p>
<p>请注意：<code>drm_gem_mmap</code>不会将内存映射到用户空间，而是依赖于驱动程序提供的<code>fault handler</code>来逐个映射页面。</p>
<h5 id="3-4-5-struct-drm-gem-object-funcs"><a href="#3-4-5-struct-drm-gem-object-funcs" class="headerlink" title="3.4.5 struct drm_gem_object_funcs"></a>3.4.5 <code>struct drm_gem_object_funcs</code></h5><p><code>struct drm_gem_object_funcs</code>定义了与<code>GEM</code>对象相关的回调函数，用于管理和操作<code>GEM</code>对象；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object_funcs</span> &#123;</span></span><br><span class="line">    <span class="type">void</span> (*<span class="built_in">free</span>)(<span class="keyword">struct</span> drm_gem_object *obj);</span><br><span class="line">    <span class="type">int</span> (*open)(<span class="keyword">struct</span> drm_gem_object *obj, <span class="keyword">struct</span> drm_file *file);</span><br><span class="line">    <span class="type">void</span> (*close)(<span class="keyword">struct</span> drm_gem_object *obj, <span class="keyword">struct</span> drm_file *file);</span><br><span class="line">    <span class="type">void</span> (*print_info)(<span class="keyword">struct</span> drm_printer *p, <span class="type">unsigned</span> <span class="type">int</span> indent, <span class="type">const</span> <span class="keyword">struct</span> drm_gem_object *obj);</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">dma_buf</span> *(*<span class="title">export</span>)(<span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span>, <span class="title">int</span> <span class="title">flags</span>);</span></span><br><span class="line">    <span class="type">int</span> (*pin)(<span class="keyword">struct</span> drm_gem_object *obj);</span><br><span class="line">    <span class="type">void</span> (*unpin)(<span class="keyword">struct</span> drm_gem_object *obj);</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sg_table</span> *(*<span class="title">get_sg_table</span>)(<span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span>);</span></span><br><span class="line">    <span class="type">int</span> (*vmap)(<span class="keyword">struct</span> drm_gem_object *obj, <span class="keyword">struct</span> iosys_map *<span class="built_in">map</span>);</span><br><span class="line">    <span class="type">void</span> (*vunmap)(<span class="keyword">struct</span> drm_gem_object *obj, <span class="keyword">struct</span> iosys_map *<span class="built_in">map</span>);</span><br><span class="line">    <span class="type">int</span> (*mmap)(<span class="keyword">struct</span> drm_gem_object *obj, <span class="keyword">struct</span> vm_area_struct *vma);</span><br><span class="line">    <span class="type">int</span> (*evict)(<span class="keyword">struct</span> drm_gem_object *obj);</span><br><span class="line">    <span class="keyword">enum</span> <span class="title function_">drm_gem_object_status</span> <span class="params">(*status)</span><span class="params">(<span class="keyword">struct</span> drm_gem_object *obj)</span>;</span><br><span class="line">    <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">vm_operations_struct</span> *<span class="title">vm_ops</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>其中：</p>
<ul>
<li><code>free</code>：用于释放<code>GEM</code>对象及其相关资源的操作，必须实现；</li>
<li><code>open</code>：创建<code>GEM handle</code>时（<code>drm_gem_handle_create</code>），回调该函数，可选；</li>
<li><code>close</code>：释放<code>GEM handle</code>时（<code>drm_gem_handle_delete</code>），回调该函数，可选；</li>
<li><code>get_sg_table</code>：用于获取<code>buffer</code>的<code>Scatter-Gather</code>表（<code>SG</code>表）；</li>
<li><code>vmap</code>：为<code>buffer</code>获取一个虚拟地址，会被<code>drm_gem_dmabuf_vmap helper</code>使用，可选；</li>
<li><code>vunmap</code>: 释放由<code>vmap</code>返回的虚拟地址，会被<code>drm_gem_dmabuf_vunmap helper</code>使用，可选；</li>
<li><code>mmap</code>：用于处理对<code>GEM</code>对象的<code>mmap</code>调用，并相应地设置<code>vma</code>（<code>vm_area_struct</code>）结构，可选；<ul>
<li>此回调函数被<code>drm_gem_mmap_obj</code>和<code>drm_gem_prime_mmap</code>两者使用；</li>
<li>当存在<code>mmap</code>时，不会使用<code>vm_ops</code>，而是必须由<code>mmap</code>回调函数设置<code>vma</code>-&gt;<code>vm_ops</code>；</li>
</ul>
</li>
<li><code>vm_ops</code>：与<code>mmap</code>一起使用的虚拟内存区域操作结构体，它包含了对应于虚拟内存区域操作的函数指针；对于<code>GEM</code>对象或其他需要通过<code>mmap</code>系统调用映射到用户空间的内核对象，必须实现适当的<code>vm_ops</code>结构体。</li>
</ul>
<h3 id="四、DRM核心数据结构"><a href="#四、DRM核心数据结构" class="headerlink" title="四、DRM核心数据结构"></a>四、<code>DRM</code>核心数据结构</h3><p>学习<code>DRM</code>驱动，首先要了解驱动框架涉及到的数据结构，知道每个数据结构以及成员的含义之后，再去看源码就容易了。</p>
<h4 id="4-1-struct-drm-device"><a href="#4-1-struct-drm-device" class="headerlink" title="4.1 struct drm_device"></a>4.1 <code>struct drm_device</code></h4><p><code>linux</code>内核使用<code>struct drm_device</code>数据结构来描述一个<code>drm</code>设备，定义在<code>include/drm/drm_device.h</code>：</p>
<details>
<summary>点击查看代码</summary>


<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_device - DRM device structure</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure represent a complete card that</span></span><br><span class="line"><span class="comment"> * may contain multiple heads.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> &#123;</span></span><br><span class="line">        <span class="comment">/** @if_version: Highest interface version set */</span></span><br><span class="line">        <span class="type">int</span> if_version;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @ref: Object ref-count */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">kref</span> <span class="title">ref</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @dev: Device structure of bus-device */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @managed:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Managed resources linked to the lifetime of this &amp;drm_device as</span></span><br><span class="line"><span class="comment">         * tracked by @ref.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">                <span class="comment">/** @managed.resources: managed resources list */</span></span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">resources</span>;</span></span><br><span class="line">                <span class="comment">/** @managed.final_kfree: pointer for final kfree() call */</span></span><br><span class="line">                <span class="type">void</span> *final_kfree;</span><br><span class="line">                <span class="comment">/** @managed.lock: protects @managed.resources */</span></span><br><span class="line">                <span class="type">spinlock_t</span> lock;</span><br><span class="line">        &#125; managed;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @driver: DRM driver managing the device */</span></span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_driver</span> *<span class="title">driver</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dev_private:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * DRM driver private data. This is deprecated and should be left set to</span></span><br><span class="line"><span class="comment">         * NULL.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Instead of using this pointer it is recommended that drivers use</span></span><br><span class="line"><span class="comment">         * devm_drm_dev_alloc() and embed struct &amp;drm_device in their larger</span></span><br><span class="line"><span class="comment">         * per-device structure.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> *dev_private;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @primary:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Primary node. Drivers should not interact with this</span></span><br><span class="line"><span class="comment">         * directly. debugfs interfaces can be registered with</span></span><br><span class="line"><span class="comment">         * drm_debugfs_add_file(), and sysfs should be directly added on the</span></span><br><span class="line"><span class="comment">         * hardware (and not character device node) struct device @dev.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">primary</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @render:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Render node. Drivers should not interact with this directly ever.</span></span><br><span class="line"><span class="comment">         * Drivers should not expose any additional interfaces in debugfs or</span></span><br><span class="line"><span class="comment">         * sysfs on this node.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">render</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @accel: Compute Acceleration node */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">accel</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @registered:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Internally used by drm_dev_register() and drm_connector_register().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> registered;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @master:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Currently active master for this device.</span></span><br><span class="line"><span class="comment">         * Protected by &amp;master_mutex</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_master</span> *<span class="title">master</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @driver_features: per-device driver features</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Drivers can clear specific flags here to disallow</span></span><br><span class="line"><span class="comment">         * certain features on a per-device basis while still</span></span><br><span class="line"><span class="comment">         * sharing a single &amp;struct drm_driver instance across</span></span><br><span class="line"><span class="comment">         * all devices.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        u32 driver_features;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @unplugged:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Flag to tell if the device has been unplugged.</span></span><br><span class="line"><span class="comment">         * See drm_dev_enter() and drm_dev_is_unplugged().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> unplugged;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @anon_inode: inode for private address-space */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">inode</span> *<span class="title">anon_inode</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @unique: Unique name of the device */</span></span><br><span class="line">        <span class="type">char</span> *unique;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @struct_mutex:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Lock for others (not &amp;drm_minor.master and &amp;drm_file.is_master)</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * WARNING:</span></span><br><span class="line"><span class="comment">         * Only drivers annotated with DRIVER_LEGACY should be using this.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">struct_mutex</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @master_mutex:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Lock for &amp;drm_minor.master and &amp;drm_file.is_master</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">master_mutex</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @open_count:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Usage counter for outstanding files open,</span></span><br><span class="line"><span class="comment">         * protected by drm_global_mutex</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">atomic_t</span> open_count;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @filelist_mutex: Protects @filelist. */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">filelist_mutex</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @filelist:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of userspace clients, linked through &amp;drm_file.lhead.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">filelist</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @filelist_internal:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of open DRM files for in-kernel clients.</span></span><br><span class="line"><span class="comment">         * Protected by &amp;filelist_mutex.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">filelist_internal</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @clientlist_mutex:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Protects &amp;clientlist access.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">clientlist_mutex</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @clientlist:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of in-kernel clients. Protected by &amp;clientlist_mutex.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">clientlist</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @vblank_disable_immediate:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * If true, vblank interrupt will be disabled immediately when the</span></span><br><span class="line"><span class="comment">         * refcount drops to zero, as opposed to via the vblank disable</span></span><br><span class="line"><span class="comment">         * timer.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This can be set to true it the hardware has a working vblank counter</span></span><br><span class="line"><span class="comment">         * with high-precision timestamping (otherwise there are races) and the</span></span><br><span class="line"><span class="comment">         * driver uses drm_crtc_vblank_on() and drm_crtc_vblank_off()</span></span><br><span class="line"><span class="comment">         * appropriately. See also @max_vblank_count and</span></span><br><span class="line"><span class="comment">         * &amp;drm_crtc_funcs.get_vblank_counter.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> vblank_disable_immediate;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @vblank:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Array of vblank tracking structures, one per &amp;struct drm_crtc. For</span></span><br><span class="line"><span class="comment">         * historical reasons (vblank support predates kernel modesetting) this</span></span><br><span class="line"><span class="comment">         * is free-standing and not part of &amp;struct drm_crtc itself. It must be</span></span><br><span class="line"><span class="comment">         * initialized explicitly by calling drm_vblank_init().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_vblank_crtc</span> *<span class="title">vblank</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @vblank_time_lock:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  Protects vblank count and time updates during vblank enable/disable</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">spinlock_t</span> vblank_time_lock;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @vbl_lock: Top-level vblank references lock, wraps the low-level</span></span><br><span class="line"><span class="comment">         * @vblank_time_lock.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">spinlock_t</span> vbl_lock;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @max_vblank_count:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Maximum value of the vblank registers. This value +1 will result in a</span></span><br><span class="line"><span class="comment">         * wrap-around of the vblank register. It is used by the vblank core to</span></span><br><span class="line"><span class="comment">         * handle wrap-arounds.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * If set to zero the vblank core will try to guess the elapsed vblanks</span></span><br><span class="line"><span class="comment">         * between times when the vblank interrupt is disabled through</span></span><br><span class="line"><span class="comment">         * high-precision timestamps. That approach is suffering from small</span></span><br><span class="line"><span class="comment">         * races and imprecision over longer time periods, hence exposing a</span></span><br><span class="line"><span class="comment">         * hardware vblank counter is always recommended.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is the statically configured device wide maximum. The driver</span></span><br><span class="line"><span class="comment">         * can instead choose to use a runtime configurable per-crtc value</span></span><br><span class="line"><span class="comment">         * &amp;drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count</span></span><br><span class="line"><span class="comment">         * must be left at zero. See drm_crtc_set_max_vblank_count() on how</span></span><br><span class="line"><span class="comment">         * to use the per-crtc value.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * If non-zero, &amp;drm_crtc_funcs.get_vblank_counter must be set.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        u32 max_vblank_count;</span><br><span class="line">        <span class="comment">/** @vblank_event_list: List of vblank events */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">vblank_event_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @event_lock:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Protects @vblank_event_list and event delivery in</span></span><br><span class="line"><span class="comment">         * general. See drm_send_event() and drm_send_event_locked().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">spinlock_t</span> event_lock;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @num_crtcs: Number of CRTCs on this device */</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">int</span> num_crtcs;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @mode_config: Current mode config */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_config</span> <span class="title">mode_config</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @object_name_lock: GEM information */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">object_name_lock</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @object_name_idr: GEM information */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">idr</span> <span class="title">object_name_idr</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @vma_offset_manager: GEM information */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_vma_offset_manager</span> *<span class="title">vma_offset_manager</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @vram_mm: VRAM MM memory manager */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_vram_mm</span> *<span class="title">vram_mm</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @switch_power_state:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Power state of the client.</span></span><br><span class="line"><span class="comment">         * Used by drivers supporting the switcheroo driver.</span></span><br><span class="line"><span class="comment">         * The state is maintained in the</span></span><br><span class="line"><span class="comment">         * &amp;vga_switcheroo_client_ops.set_gpu_state callback</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">enum</span> <span class="title">switch_power_state</span> <span class="title">switch_power_state</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @fb_helper:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Pointer to the fbdev emulation structure.</span></span><br><span class="line"><span class="comment">         * Set by drm_fb_helper_init() and cleared by drm_fb_helper_fini().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_fb_helper</span> *<span class="title">fb_helper</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @debugfs_mutex:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Protects &amp;debugfs_list access.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">debugfs_mutex</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @debugfs_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of debugfs files to be created by the DRM device. The files</span></span><br><span class="line"><span class="comment">         * must be added during drm_dev_register().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">debugfs_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Everything below here is for legacy driver, never use! */</span></span><br><span class="line">        <span class="comment">/* private: */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> IS_ENABLED(CONFIG_DRM_LEGACY)</span></span><br><span class="line">        <span class="comment">/* List of devices per driver for stealth attach cleanup */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">legacy_dev_list</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __alpha__</span></span><br><span class="line">        <span class="comment">/** @hose: PCI hose, only used on ALPHA platforms. */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">pci_controller</span> *<span class="title">hose</span>;</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* AGP data */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_agp_head</span> *<span class="title">agp</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Context handle management - linked list of context handles */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">ctxlist</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Context handle management - mutex for &amp;ctxlist */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">ctxlist_mutex</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Context handle management */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">idr</span> <span class="title">ctx_idr</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Memory management - linked list of regions */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">maplist</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Memory management - user token hash table for maps */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_open_hash</span> <span class="title">map_hash</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Context handle management - list of vmas (for debugging) */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">vmalist</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Optional pointer for DMA support */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device_dma</span> *<span class="title">dma</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Context swapping flag */</span></span><br><span class="line">        __volatile__ <span class="type">long</span> context_flag;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Last current context */</span></span><br><span class="line">        <span class="type">int</span> last_context;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Lock for &amp;buf_use and a few other things. */</span></span><br><span class="line">        <span class="type">spinlock_t</span> buf_lock;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Usage counter for buffers in use -- cannot alloc */</span></span><br><span class="line">        <span class="type">int</span> buf_use;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Buffer allocation in progress */</span></span><br><span class="line">        <span class="type">atomic_t</span> buf_alloc;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">                <span class="type">int</span> context;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">drm_hw_lock</span> *<span class="title">lock</span>;</span></span><br><span class="line">        &#125; sigdata;</span><br><span class="line"></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_local_map</span> *<span class="title">agp_buffer_map</span>;</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">int</span> agp_buffer_token;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Scatter gather memory */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_sg_mem</span> *<span class="title">sg</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* IRQs */</span></span><br><span class="line">        <span class="type">bool</span> irq_enabled;</span><br><span class="line">        <span class="type">int</span> irq;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

</details>

<p>初识这个数据结构，我们发现这个数据结构包含的字段属实有点多，如果要将每个字段的含义都搞清楚，定然不是一件容易的事情，因此我们只关注如下字段即可：</p>
<ul>
<li><code>ref</code>：具有动态生命周期的对象的引用计数，对象的初始引用计数为1，使用<code>drm_dev_get</code>和<code>drm_dev_put</code>获取和释放进一步的引用计数；</li>
<li><code>dev</code>：设备驱动模型中的<code>device</code>，可以将<code>drm_device</code>看做其子类；</li>
<li><code>driver</code>：<code>drm</code>驱动；</li>
<li><code>registered</code>：设备是否已注册；</li>
<li><code>unique</code>：设备的唯一名称；</li>
<li><code>vblank_event_list</code>：<code>vblank</code>事件链表；</li>
<li><code>num_crtcs</code>：<code>CRTC</code>的数量；</li>
<li><code>debugfs_list</code>：保存<code>struct drm_debugfs_entry</code>的链表；</li>
<li><code>mode_config</code>：当前的显示模式配置，<code>struct drm_mode_config</code>类型。</li>
</ul>
<h5 id="4-1-1-struct-drm-minor"><a href="#4-1-1-struct-drm-minor" class="headerlink" title="4.1.1 struct drm_minor"></a>4.1.1 <code>struct drm_minor</code></h5><p>在<code>struct drm_device</code>数据结构中，<code>primary</code>、<code>render</code>、<code>accel</code>字段都是<code>struct drm_minor</code>类型。</p>
<p>这个数据结构和我们在<code>ALSA</code>中介绍的<code> struct snd_minor</code>是非常相似的，其创建和注册分别通过<code>drm_minor_alloc</code>和<code>drm_minor_register</code>实现。</p>
<p><code>struct drm_minor</code>定义在<code>include/drm/drm_file.h</code>，<code>DRM core</code>会根据<code>driver_features</code>来决定是否为<code>drm_device</code>中的<code>primary</code>、<code>render</code>、<code>accel</code>注册字符设备（同时在<code>/dev/dri</code>目录下创建相应的设备节点），比如<code>/dev/dri/card0</code>、<code>/dev/dri/renderD128</code>等；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * <span class="doctag">FIXME:</span> Not sure we want to have drm_minor here in the end, but to avoid</span></span><br><span class="line"><span class="comment"> * header include loops we need it here for now.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Note that the order of this enum is ABI (it determines</span></span><br><span class="line"><span class="comment"> * /dev/dri/renderD* numbers).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Setting DRM_MINOR_ACCEL to 32 gives enough space for more drm minors to</span></span><br><span class="line"><span class="comment"> * be implemented before we hit any future</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">drm_minor_type</span> &#123;</span></span><br><span class="line">        DRM_MINOR_PRIMARY,</span><br><span class="line">        DRM_MINOR_CONTROL,</span><br><span class="line">        DRM_MINOR_RENDER,</span><br><span class="line">        DRM_MINOR_ACCEL = <span class="number">32</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_minor - DRM device minor structure</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure represents a DRM minor number for device nodes in /dev.</span></span><br><span class="line"><span class="comment"> * Entirely opaque to drivers and should never be inspected directly by drivers.</span></span><br><span class="line"><span class="comment"> * Drivers instead should only interact with &amp;struct drm_file and of course</span></span><br><span class="line"><span class="comment"> * &amp;struct drm_device, which is also where driver-private data and resources can</span></span><br><span class="line"><span class="comment"> * be attached to.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> &#123;</span></span><br><span class="line">        <span class="comment">/* private: */</span></span><br><span class="line">        <span class="type">int</span> index;                      <span class="comment">/* Minor device number */</span></span><br><span class="line">        <span class="type">int</span> type;                       <span class="comment">/* Control or render or accel */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">kdev</span>;</span>            <span class="comment">/* Linux device */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">dentry</span> *<span class="title">debugfs_root</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">debugfs_list</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">debugfs_lock</span>;</span> <span class="comment">/* Protects debugfs_list. */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>其中：</p>
<ul>
<li><code>index</code>：次设备号；</li>
<li><code>type</code>：<code>drm</code>设备类型；</li>
<li><code>kdev</code>：设备驱动模型中的<code>device</code>；</li>
<li><code>dev</code>：<code>drm</code>设备；</li>
<li><code>debugfs_root</code>：<code>deugfs</code>目录项；</li>
<li><code>debugfs_list</code>：与<code>debugfs</code>有关的链表，链表中存放的都是<code>struct drm_debugfs_entry</code>；</li>
</ul>
<p><code>struct drm_debugfs_entry</code>定义在<code>include/drm/drm_debugfs.h</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_debugfs_info - debugfs info list entry</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure represents a debugfs file to be created by the drm</span></span><br><span class="line"><span class="comment"> * core. 描述debugfs文件信息</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_info</span> &#123;</span></span><br><span class="line">        <span class="comment">/** @name: File name */</span></span><br><span class="line">        <span class="type">const</span> <span class="type">char</span> *name;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @show:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Show callback. &amp;seq_file-&gt;private will be set to the &amp;struct</span></span><br><span class="line"><span class="comment">         * drm_debugfs_entry corresponding to the instance of this info</span></span><br><span class="line"><span class="comment">         * on a given &amp;struct drm_device.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*show)(<span class="keyword">struct</span> seq_file*, <span class="type">void</span>*);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @driver_features: Required driver features for this entry. */</span></span><br><span class="line">        u32 driver_features;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @data: Driver-private data, should not be device-specific. */</span></span><br><span class="line">        <span class="type">void</span> *data;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_debugfs_entry - Per-device debugfs node structure</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure represents a debugfs file, as an instantiation of a &amp;struct</span></span><br><span class="line"><span class="comment"> * drm_debugfs_info on a &amp;struct drm_device.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_entry</span> &#123;</span></span><br><span class="line">        <span class="comment">/** @dev: &amp;struct drm_device for this node. */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @file: Template for this node. */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_info</span> <span class="title">file</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @list: Linked list of all device nodes. */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">list</span>;</span>  <span class="comment">// 链表节点，用于将当节点添加到drm设备的debugfs_list链表中</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h5 id="4-1-2-struct-drm-mode-config"><a href="#4-1-2-struct-drm-mode-config" class="headerlink" title="4.1.2 struct drm_mode_config"></a>4.1.2 <code>struct drm_mode_config</code></h5><p><code>linux</code>内核使用<code>struct drm_mode_config</code>来描述显示模式配置信息，<code>drm_mode_config</code>的主要功能之一是提供对显示器模式的管理和配置。这包括添加、删除、修改和查询显示器模式的能力。此外，<code>drm_mode_config</code>还提供了与模式相关的配置选项，例如色彩空间、刷新率、分辨率等等。</p>
<p><code>struct drm_mode_config</code>定义在<code>include/drm/drm_mode_config.h</code>：</p>
<details>
<summary>点击查看代码</summary>


<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_mode_config - Mode configuration control structure</span></span><br><span class="line"><span class="comment"> * @min_width: minimum fb pixel width on this device</span></span><br><span class="line"><span class="comment"> * @min_height: minimum fb pixel height on this device</span></span><br><span class="line"><span class="comment"> * @max_width: maximum fb pixel width on this device</span></span><br><span class="line"><span class="comment"> * @max_height: maximum fb pixel height on this device</span></span><br><span class="line"><span class="comment"> * @funcs: core driver provided mode setting functions</span></span><br><span class="line"><span class="comment"> * @poll_enabled: track polling support for this device</span></span><br><span class="line"><span class="comment"> * @poll_running: track polling status for this device</span></span><br><span class="line"><span class="comment"> * @delayed_event: track delayed poll uevent deliver for this device</span></span><br><span class="line"><span class="comment"> * @output_poll_work: delayed work for polling in process context</span></span><br><span class="line"><span class="comment"> * @preferred_depth: preferred RBG pixel depth, used by fb helpers</span></span><br><span class="line"><span class="comment"> * @prefer_shadow: hint to userspace to prefer shadow-fb rendering</span></span><br><span class="line"><span class="comment"> * @cursor_width: hint to userspace for max cursor width</span></span><br><span class="line"><span class="comment"> * @cursor_height: hint to userspace for max cursor height</span></span><br><span class="line"><span class="comment"> * @helper_private: mid-layer private data</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Core mode resource tracking structure.  All CRTC, encoders, and connectors</span></span><br><span class="line"><span class="comment"> * enumerated by the driver are added here, as are global properties.  Some</span></span><br><span class="line"><span class="comment"> * global restrictions are also here, e.g. dimension restrictions.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Framebuffer sizes refer to the virtual screen that can be displayed by</span></span><br><span class="line"><span class="comment"> * the CRTC. This can be different from the physical resolution programmed.</span></span><br><span class="line"><span class="comment"> * The minimum width and height, stored in @min_width and @min_height,</span></span><br><span class="line"><span class="comment"> * describe the smallest size of the framebuffer. It correlates to the</span></span><br><span class="line"><span class="comment"> * minimum programmable resolution.</span></span><br><span class="line"><span class="comment"> * The maximum width, stored in @max_width, is typically limited by the</span></span><br><span class="line"><span class="comment"> * maximum pitch between two adjacent scanlines. The maximum height, stored</span></span><br><span class="line"><span class="comment"> * in @max_height, is usually only limited by the amount of addressable video</span></span><br><span class="line"><span class="comment"> * memory. For hardware that has no real maximum, drivers should pick a</span></span><br><span class="line"><span class="comment"> * reasonable default.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * See also @DRM_SHADOW_PLANE_MAX_WIDTH and @DRM_SHADOW_PLANE_MAX_HEIGHT.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_config</span> &#123;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @mutex:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is the big scary modeset BKL which protects everything that</span></span><br><span class="line"><span class="comment">         * isn&#x27;t protect otherwise. Scope is unclear and fuzzy, try to remove</span></span><br><span class="line"><span class="comment">         * anything from under its protection and move it into more well-scoped</span></span><br><span class="line"><span class="comment">         * locks.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The one important thing this protects is the use of @acquire_ctx.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">mutex</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @connection_mutex:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This protects connector state and the connector to encoder to CRTC</span></span><br><span class="line"><span class="comment">         * routing chain.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * For atomic drivers specifically this protects &amp;drm_connector.state.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_modeset_lock</span> <span class="title">connection_mutex</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @acquire_ctx:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Global implicit acquire context used by atomic drivers for legacy</span></span><br><span class="line"><span class="comment">         * IOCTLs. Deprecated, since implicit locking contexts make it</span></span><br><span class="line"><span class="comment">         * impossible to use driver-private &amp;struct drm_modeset_lock. Users of</span></span><br><span class="line"><span class="comment">         * this must hold @mutex.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_modeset_acquire_ctx</span> *<span class="title">acquire_ctx</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @idr_mutex:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Mutex for KMS ID allocation and management. Protects both @object_idr</span></span><br><span class="line"><span class="comment">         * and @tile_idr.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">idr_mutex</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @object_idr:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Main KMS ID tracking object. Use this idr for all IDs, fb, crtc,</span></span><br><span class="line"><span class="comment">         * connector, modes - just makes life easier to have only one.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">idr</span> <span class="title">object_idr</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @tile_idr:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Use this idr for allocating new IDs for tiled sinks like use in some</span></span><br><span class="line"><span class="comment">         * high-res DP MST screens.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">idr</span> <span class="title">tile_idr</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @fb_lock: Mutex to protect fb the global @fb_list and @num_fb. */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">fb_lock</span>;</span></span><br><span class="line">        <span class="comment">/** @num_fb: Number of entries on @fb_list. */</span></span><br><span class="line">        <span class="type">int</span> num_fb;</span><br><span class="line">        <span class="comment">/** @fb_list: List of all &amp;struct drm_framebuffer. */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">fb_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @connector_list_lock: Protects @num_connector and</span></span><br><span class="line"><span class="comment">         * @connector_list and @connector_free_list.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">spinlock_t</span> connector_list_lock;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @num_connector: Number of connectors on this device. Protected by</span></span><br><span class="line"><span class="comment">         * @connector_list_lock.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> num_connector;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @connector_ida: ID allocator for connector indices.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">ida</span> <span class="title">connector_ida</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @connector_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of connector objects linked with &amp;drm_connector.head. Protected</span></span><br><span class="line"><span class="comment">         * by @connector_list_lock. Only use drm_for_each_connector_iter() and</span></span><br><span class="line"><span class="comment">         * &amp;struct drm_connector_list_iter to walk this list.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">connector_list</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @connector_free_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of connector objects linked with &amp;drm_connector.free_head.</span></span><br><span class="line"><span class="comment">         * Protected by @connector_list_lock. Used by</span></span><br><span class="line"><span class="comment">         * drm_for_each_connector_iter() and</span></span><br><span class="line"><span class="comment">         * &amp;struct drm_connector_list_iter to savely free connectors using</span></span><br><span class="line"><span class="comment">         * @connector_free_work.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">llist_head</span> <span class="title">connector_free_list</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @connector_free_work: Work to clean up @connector_free_list.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">work_struct</span> <span class="title">connector_free_work</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @num_encoder:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Number of encoders on this device. This is invariant over the</span></span><br><span class="line"><span class="comment">         * lifetime of a device and hence doesn&#x27;t need any locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> num_encoder;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @encoder_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of encoder objects linked with &amp;drm_encoder.head. This is</span></span><br><span class="line"><span class="comment">         * invariant over the lifetime of a device and hence doesn&#x27;t need any</span></span><br><span class="line"><span class="comment">         * locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">encoder_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @num_total_plane:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Number of universal (i.e. with primary/curso) planes on this device.</span></span><br><span class="line"><span class="comment">         * This is invariant over the lifetime of a device and hence doesn&#x27;t</span></span><br><span class="line"><span class="comment">         * need any locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> num_total_plane;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @plane_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of plane objects linked with &amp;drm_plane.head. This is invariant</span></span><br><span class="line"><span class="comment">         * over the lifetime of a device and hence doesn&#x27;t need any locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">plane_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @num_crtc:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Number of CRTCs on this device linked with &amp;drm_crtc.head. This is invariant over the lifetime</span></span><br><span class="line"><span class="comment">         * of a device and hence doesn&#x27;t need any locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> num_crtc;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @crtc_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of CRTC objects linked with &amp;drm_crtc.head. This is invariant</span></span><br><span class="line"><span class="comment">         * over the lifetime of a device and hence doesn&#x27;t need any locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">crtc_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @property_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of property type objects linked with &amp;drm_property.head. This is</span></span><br><span class="line"><span class="comment">         * invariant over the lifetime of a device and hence doesn&#x27;t need any</span></span><br><span class="line"><span class="comment">         * locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">property_list</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @privobj_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of private objects linked with &amp;drm_private_obj.head. This is</span></span><br><span class="line"><span class="comment">         * invariant over the lifetime of a device and hence doesn&#x27;t need any</span></span><br><span class="line"><span class="comment">         * locks.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">privobj_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> min_width, min_height;</span><br><span class="line">        <span class="type">int</span> max_width, max_height;</span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_config_funcs</span> *<span class="title">funcs</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* output poll support */</span></span><br><span class="line">        <span class="type">bool</span> poll_enabled;</span><br><span class="line">        <span class="type">bool</span> poll_running;</span><br><span class="line">        <span class="type">bool</span> delayed_event;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">delayed_work</span> <span class="title">output_poll_work</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @blob_lock:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Mutex for blob property allocation and management, protects</span></span><br><span class="line"><span class="comment">         * @property_blob_list and &amp;drm_file.blobs.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">blob_lock</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @property_blob_list:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * List of all the blob property objects linked with</span></span><br><span class="line"><span class="comment">         * &amp;drm_property_blob.head. Protected by @blob_lock.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">property_blob_list</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* pointers to standard properties */</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @edid_property: Default connector property to hold the EDID of the</span></span><br><span class="line"><span class="comment">         * currently connected sink, if any.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span> *<span class="title">edid_property</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dpms_property: Default connector property to control the</span></span><br><span class="line"><span class="comment">         * connector&#x27;s DPMS state.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span> *<span class="title">dpms_property</span>;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @path_property: Default connector property to hold the DP MST path</span></span><br><span class="line"><span class="comment">         * for the port.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span> *<span class="title">path_property</span>;</span></span><br><span class="line">   </span><br><span class="line">        .... 大量的<span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span></span></span><br><span class="line"><span class="class">            </span></span><br><span class="line"><span class="class">        /**</span></span><br><span class="line"><span class="class">         * @<span class="title">hdcp_content_type_property</span>:</span> DRM ENUM property <span class="keyword">for</span> type of</span><br><span class="line">         * Protected Content.</span><br><span class="line">         */</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span> *<span class="title">hdcp_content_type_property</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* dumb ioctl parameters */</span></span><br><span class="line">        <span class="type">uint32_t</span> preferred_depth, prefer_shadow;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @prefer_shadow_fbdev:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Hint to framebuffer emulation to prefer shadow-fb rendering.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> prefer_shadow_fbdev;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @quirk_addfb_prefer_xbgr_30bpp:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Special hack for legacy ADDFB to keep nouveau userspace happy. Should</span></span><br><span class="line"><span class="comment">         * only ever be set by the nouveau kernel driver.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> quirk_addfb_prefer_xbgr_30bpp;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @quirk_addfb_prefer_host_byte_order:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * When set to true drm_mode_addfb() will pick host byte order</span></span><br><span class="line"><span class="comment">         * pixel_format when calling drm_mode_addfb2().  This is how</span></span><br><span class="line"><span class="comment">         * drm_mode_addfb() should have worked from day one.  It</span></span><br><span class="line"><span class="comment">         * didn&#x27;t though, so we ended up with quirks in both kernel</span></span><br><span class="line"><span class="comment">         * and userspace drivers to deal with the broken behavior.</span></span><br><span class="line"><span class="comment">         * Simply fixing drm_mode_addfb() unconditionally would break</span></span><br><span class="line"><span class="comment">         * these drivers, so add a quirk bit here to allow drivers</span></span><br><span class="line"><span class="comment">         * opt-in.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> quirk_addfb_prefer_host_byte_order;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @async_page_flip: Does this device support async flips on the primary</span></span><br><span class="line"><span class="comment">         * plane?</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> async_page_flip;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @fb_modifiers_not_supported:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * When this flag is set, the DRM device will not expose modifier</span></span><br><span class="line"><span class="comment">         * support to userspace. This is only used by legacy drivers that infer</span></span><br><span class="line"><span class="comment">         * the buffer layout through heuristics without using modifiers. New</span></span><br><span class="line"><span class="comment">         * drivers shall not set fhis flag.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> fb_modifiers_not_supported;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @normalize_zpos:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * If true the drm core will call drm_atomic_normalize_zpos() as part of</span></span><br><span class="line"><span class="comment">         * atomic mode checking from drm_atomic_helper_check()</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">bool</span> normalize_zpos;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @modifiers_property: Plane property to list support modifier/format</span></span><br><span class="line"><span class="comment">         * combination.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_property</span> *<span class="title">modifiers_property</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* cursor size */</span></span><br><span class="line">        <span class="type">uint32_t</span> cursor_width, cursor_height;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @suspend_state:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Atomic state when suspended.</span></span><br><span class="line"><span class="comment">         * Set by drm_mode_config_helper_suspend() and cleared by</span></span><br><span class="line"><span class="comment">         * drm_mode_config_helper_resume().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_atomic_state</span> *<span class="title">suspend_state</span>;</span></span><br><span class="line"></span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_config_helper_funcs</span> *<span class="title">helper_private</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

</details>

<p>同样，我们只关系核心字段：</p>
<ul>
<li><code>min_width</code> 和 <code>min_height</code>：设备上支持的最小帧缓冲区像素宽度和高度；</li>
<li><code>max_width</code> 和 <code>max_height</code>：设备上支持的最大帧缓冲区像素宽度和高度；</li>
<li><code>funcs</code>：由核心驱动程序提供的模式设置函数，<code>struct drm_mode_config_funcs *</code>类型；</li>
<li><code>cursor_width</code> 和 <code>cursor_height</code>：向用户空间提供关于光标最大宽度和高度的提示；</li>
<li><code>helper_private</code>：中间层私有数据，<code>struct drm_mode_config_helper_funcs *</code>类型；</li>
</ul>
<h5 id="4-1-3-struct-drm-mode-config-funcs"><a href="#4-1-3-struct-drm-mode-config-funcs" class="headerlink" title="4.1.3 struct drm_mode_config_funcs"></a>4.1.3 <code>struct drm_mode_config_funcs</code></h5><p>在<code>struct drm_mode_config</code>结构体中存在一个类型为<code>struct drm_mode_config_funcs</code>的回调函数<code>funcs</code>.</p>
<p><code>drm_mode_config_func</code>是一个函数指针结构体，用于驱动程序向内核注册显示器模式配置（<code>Mode Setting</code>）的回调函数。这些函数指针包括添加和删除连接器<code>CRTC</code>和编解码器，以及更新显示模式等功能。</p>
<p>当内核需要对显示器模式进行配置或管理时，它将调用这些回调函数以执行相应操作。</p>
<p><code>struct drm_mode_config_funcs</code>定义在<code>include/drm/drm_mode_config.h</code>：</p>
<details>
<summary>点击查看代码</summary>


<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_mode_config_funcs - basic driver provided mode setting functions</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that</span></span><br><span class="line"><span class="comment"> * involve drivers.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_config_funcs</span> &#123;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @fb_create:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Create a new framebuffer object. The core does basic checks on the</span></span><br><span class="line"><span class="comment">         * requested metadata, but most of that is left to the driver. See</span></span><br><span class="line"><span class="comment">         * &amp;struct drm_mode_fb_cmd2 for details.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * To validate the pixel format and modifier drivers can use</span></span><br><span class="line"><span class="comment">         * drm_any_plane_has_format() to make sure at least one plane supports</span></span><br><span class="line"><span class="comment">         * the requested values. Note that the driver must first determine the</span></span><br><span class="line"><span class="comment">         * actual modifier used if the request doesn&#x27;t have it specified,</span></span><br><span class="line"><span class="comment">         * ie. when (@mode_cmd-&gt;flags &amp; DRM_MODE_FB_MODIFIERS) == 0.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * IMPORTANT: These implied modifiers for legacy userspace must be</span></span><br><span class="line"><span class="comment">         * stored in struct &amp;drm_framebuffer, including all relevant metadata</span></span><br><span class="line"><span class="comment">         * like &amp;drm_framebuffer.pitches and &amp;drm_framebuffer.offsets if the</span></span><br><span class="line"><span class="comment">         * modifier enables additional planes beyond the fourcc pixel format</span></span><br><span class="line"><span class="comment">         * code. This is required by the GETFB2 ioctl.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * If the parameters are deemed valid and the backing storage objects in</span></span><br><span class="line"><span class="comment">         * the underlying memory manager all exist, then the driver allocates</span></span><br><span class="line"><span class="comment">         * a new &amp;drm_framebuffer structure, subclassed to contain</span></span><br><span class="line"><span class="comment">         * driver-specific information (like the internal native buffer object</span></span><br><span class="line"><span class="comment">         * references). It also needs to fill out all relevant metadata, which</span></span><br><span class="line"><span class="comment">         * should be done by calling drm_helper_mode_fill_fb_struct().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The initialization is finalized by calling drm_framebuffer_init(),</span></span><br><span class="line"><span class="comment">         * which registers the framebuffer and makes it accessible to other</span></span><br><span class="line"><span class="comment">         * threads.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * RETURNS:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * A new framebuffer with an initial reference count of 1 or a negative</span></span><br><span class="line"><span class="comment">         * error code encoded with ERR_PTR().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_framebuffer</span> *(*<span class="title">fb_create</span>)(<span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>,</span></span><br><span class="line"><span class="class">                                             <span class="keyword">struct</span> <span class="title">drm_file</span> *<span class="title">file_priv</span>,</span></span><br><span class="line"><span class="class">                                             <span class="title">const</span> <span class="keyword">struct</span> <span class="title">drm_mode_fb_cmd2</span> *<span class="title">mode_cmd</span>);</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @get_format_info:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Allows a driver to return custom format information for special</span></span><br><span class="line"><span class="comment">         * fb layouts (eg. ones with auxiliary compression control planes).</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * RETURNS:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The format information specific to the given fb metadata, or</span></span><br><span class="line"><span class="comment">         * NULL if none is found.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_format_info</span> *(*<span class="title">get_format_info</span>)(<span class="title">const</span> <span class="keyword">struct</span> <span class="title">drm_mode_fb_cmd2</span> *<span class="title">mode_cmd</span>);</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @output_poll_changed:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Callback used by helpers to inform the driver of output configuration</span></span><br><span class="line"><span class="comment">         * changes.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Drivers implementing fbdev emulation use drm_kms_helper_hotplug_event()</span></span><br><span class="line"><span class="comment">         * to call this hook to inform the fbdev helper of output changes.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This hook is deprecated, drivers should instead use</span></span><br><span class="line"><span class="comment">         * drm_fbdev_generic_setup() which takes care of any necessary</span></span><br><span class="line"><span class="comment">         * hotplug event forwarding already without further involvement by</span></span><br><span class="line"><span class="comment">         * the driver.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*output_poll_changed)(<span class="keyword">struct</span> drm_device *dev);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @mode_valid:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Device specific validation of display modes. Can be used to reject</span></span><br><span class="line"><span class="comment">         * modes that can never be supported. Only device wide constraints can</span></span><br><span class="line"><span class="comment">         * be checked here. crtc/encoder/bridge/connector specific constraints</span></span><br><span class="line"><span class="comment">         * should be checked in the .mode_valid() hook for each specific object.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">enum</span> <span class="title function_">drm_mode_status</span> <span class="params">(*mode_valid)</span><span class="params">(<span class="keyword">struct</span> drm_device *dev,</span></span><br><span class="line"><span class="params">                                           <span class="type">const</span> <span class="keyword">struct</span> drm_display_mode *mode)</span>;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @atomic_check:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is the only hook to validate an atomic modeset update. This</span></span><br><span class="line"><span class="comment">         * function must reject any modeset and state changes which the hardware</span></span><br><span class="line"><span class="comment">         * or driver doesn&#x27;t support. This includes but is of course not limited</span></span><br><span class="line"><span class="comment">         * to:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - Checking that the modes, framebuffers, scaling and placement</span></span><br><span class="line"><span class="comment">         *    requirements and so on are within the limits of the hardware.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - Checking that any hidden shared resources are not oversubscribed.</span></span><br><span class="line"><span class="comment">         *    This can be shared PLLs, shared lanes, overall memory bandwidth,</span></span><br><span class="line"><span class="comment">         *    display fifo space (where shared between planes or maybe even</span></span><br><span class="line"><span class="comment">         *    CRTCs).</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - Checking that virtualized resources exported to userspace are not</span></span><br><span class="line"><span class="comment">         *    oversubscribed. For various reasons it can make sense to expose</span></span><br><span class="line"><span class="comment">         *    more planes, crtcs or encoders than which are physically there. One</span></span><br><span class="line"><span class="comment">         *    example is dual-pipe operations (which generally should be hidden</span></span><br><span class="line"><span class="comment">         *    from userspace if when lockstepped in hardware, exposed otherwise),</span></span><br><span class="line"><span class="comment">         *    where a plane might need 1 hardware plane (if it&#x27;s just on one</span></span><br><span class="line"><span class="comment">         *    pipe), 2 hardware planes (when it spans both pipes) or maybe even</span></span><br><span class="line"><span class="comment">         *    shared a hardware plane with a 2nd plane (if there&#x27;s a compatible</span></span><br><span class="line"><span class="comment">         *    plane requested on the area handled by the other pipe).</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - Check that any transitional state is possible and that if</span></span><br><span class="line"><span class="comment">         *    requested, the update can indeed be done in the vblank period</span></span><br><span class="line"><span class="comment">         *    without temporarily disabling some functions.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - Check any other constraints the driver or hardware might have.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - This callback also needs to correctly fill out the &amp;drm_crtc_state</span></span><br><span class="line"><span class="comment">         *    in this update to make sure that drm_atomic_crtc_needs_modeset()</span></span><br><span class="line"><span class="comment">         *    reflects the nature of the possible update and returns true if and</span></span><br><span class="line"><span class="comment">         *    only if the update cannot be applied without tearing within one</span></span><br><span class="line"><span class="comment">         *    vblank on that CRTC. The core uses that information to reject</span></span><br><span class="line"><span class="comment">         *    updates which require a full modeset (i.e. blanking the screen, or</span></span><br><span class="line"><span class="comment">         *    at least pausing updates for a substantial amount of time) if</span></span><br><span class="line"><span class="comment">         *    userspace has disallowed that in its request.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - The driver also does not need to repeat basic input validation</span></span><br><span class="line"><span class="comment">         *    like done for the corresponding legacy entry points. The core does</span></span><br><span class="line"><span class="comment">         *    that before calling this hook.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * See the documentation of @atomic_commit for an exhaustive list of</span></span><br><span class="line"><span class="comment">         * error conditions which don&#x27;t have to be checked at the in this</span></span><br><span class="line"><span class="comment">         * callback.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * See the documentation for &amp;struct drm_atomic_state for how exactly</span></span><br><span class="line"><span class="comment">         * an atomic modeset update is described.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Drivers using the atomic helpers can implement this hook using</span></span><br><span class="line"><span class="comment">         * drm_atomic_helper_check(), or one of the exported sub-functions of</span></span><br><span class="line"><span class="comment">         * it.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * RETURNS:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * 0 on success or one of the below negative error codes:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -EINVAL, if any of the above constraints are violated.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -EDEADLK, when returned from an attempt to acquire an additional</span></span><br><span class="line"><span class="comment">         *    &amp;drm_modeset_lock through drm_modeset_lock().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -ENOMEM, if allocating additional state sub-structures failed due</span></span><br><span class="line"><span class="comment">         *    to lack of memory.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted.</span></span><br><span class="line"><span class="comment">         *    This can either be due to a pending signal, or because the driver</span></span><br><span class="line"><span class="comment">         *    needs to completely bail out to recover from an exceptional</span></span><br><span class="line"><span class="comment">         *    situation like a GPU hang. From a userspace point all errors are</span></span><br><span class="line"><span class="comment">         *    treated equally.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*<span class="type">atomic_check</span>)(<span class="keyword">struct</span> drm_device *dev,</span><br><span class="line">                            <span class="keyword">struct</span> drm_atomic_state *state);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @atomic_commit:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is the only hook to commit an atomic modeset update. The core</span></span><br><span class="line"><span class="comment">         * guarantees that @atomic_check has been called successfully before</span></span><br><span class="line"><span class="comment">         * calling this function, and that nothing has been changed in the</span></span><br><span class="line"><span class="comment">         * interim.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * See the documentation for &amp;struct drm_atomic_state for how exactly</span></span><br><span class="line"><span class="comment">         * an atomic modeset update is described.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Drivers using the atomic helpers can implement this hook using</span></span><br><span class="line"><span class="comment">         * drm_atomic_helper_commit(), or one of the exported sub-functions of</span></span><br><span class="line"><span class="comment">         * it.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Nonblocking commits (as indicated with the nonblock parameter) must</span></span><br><span class="line"><span class="comment">         * do any preparatory work which might result in an unsuccessful commit</span></span><br><span class="line"><span class="comment">         * in the context of this callback. The only exceptions are hardware</span></span><br><span class="line"><span class="comment">         * errors resulting in -EIO. But even in that case the driver must</span></span><br><span class="line"><span class="comment">         * ensure that the display pipe is at least running, to avoid</span></span><br><span class="line"><span class="comment">         * compositors crashing when pageflips don&#x27;t work. Anything else,</span></span><br><span class="line"><span class="comment">         * specifically committing the update to the hardware, should be done</span></span><br><span class="line"><span class="comment">         * without blocking the caller. For updates which do not require a</span></span><br><span class="line"><span class="comment">         * modeset this must be guaranteed.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The driver must wait for any pending rendering to the new</span></span><br><span class="line"><span class="comment">         * framebuffers to complete before executing the flip. It should also</span></span><br><span class="line"><span class="comment">         * wait for any pending rendering from other drivers if the underlying</span></span><br><span class="line"><span class="comment">         * buffer is a shared dma-buf. Nonblocking commits must not wait for</span></span><br><span class="line"><span class="comment">         * rendering in the context of this callback.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * An application can request to be notified when the atomic commit has</span></span><br><span class="line"><span class="comment">         * completed. These events are per-CRTC and can be distinguished by the</span></span><br><span class="line"><span class="comment">         * CRTC index supplied in &amp;drm_event to userspace.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The drm core will supply a &amp;struct drm_event in each CRTC&#x27;s</span></span><br><span class="line"><span class="comment">         * &amp;drm_crtc_state.event. See the documentation for</span></span><br><span class="line"><span class="comment">         * &amp;drm_crtc_state.event for more details about the precise semantics of</span></span><br><span class="line"><span class="comment">         * this event.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * <span class="doctag">NOTE:</span></span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Drivers are not allowed to shut down any display pipe successfully</span></span><br><span class="line"><span class="comment">         * enabled through an atomic commit on their own. Doing so can result in</span></span><br><span class="line"><span class="comment">         * compositors crashing if a page flip is suddenly rejected because the</span></span><br><span class="line"><span class="comment">         * pipe is off.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * RETURNS:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * 0 on success or one of the below negative error codes:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -EBUSY, if a nonblocking updated is requested and there is</span></span><br><span class="line"><span class="comment">         *    an earlier updated pending. Drivers are allowed to support a queue</span></span><br><span class="line"><span class="comment">         *    of outstanding updates, but currently no driver supports that.</span></span><br><span class="line"><span class="comment">         *    Note that drivers must wait for preceding updates to complete if a</span></span><br><span class="line"><span class="comment">         *    synchronous update is requested, they are not allowed to fail the</span></span><br><span class="line"><span class="comment">         *    commit in that case.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -ENOMEM, if the driver failed to allocate memory. Specifically</span></span><br><span class="line"><span class="comment">         *    this can happen when trying to pin framebuffers, which must only</span></span><br><span class="line"><span class="comment">         *    be done when committing the state.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -ENOSPC, as a refinement of the more generic -ENOMEM to indicate</span></span><br><span class="line"><span class="comment">         *    that the driver has run out of vram, iommu space or similar GPU</span></span><br><span class="line"><span class="comment">         *    address space needed for framebuffer.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -EIO, if the hardware completely died.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         *  - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted.</span></span><br><span class="line"><span class="comment">         *    This can either be due to a pending signal, or because the driver</span></span><br><span class="line"><span class="comment">         *    needs to completely bail out to recover from an exceptional</span></span><br><span class="line"><span class="comment">         *    situation like a GPU hang. From a userspace point of view all errors are</span></span><br><span class="line"><span class="comment">         *    treated equally.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This list is exhaustive. Specifically this hook is not allowed to</span></span><br><span class="line"><span class="comment">         * return -EINVAL (any invalid requests should be caught in</span></span><br><span class="line"><span class="comment">         * @atomic_check) or -EDEADLK (this function must not acquire</span></span><br><span class="line"><span class="comment">         * additional modeset locks).</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*<span class="type">atomic_commit</span>)(<span class="keyword">struct</span> drm_device *dev,</span><br><span class="line">                             <span class="keyword">struct</span> drm_atomic_state *state,</span><br><span class="line">                             <span class="type">bool</span> nonblock);</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @atomic_state_alloc:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This optional hook can be used by drivers that want to subclass struct</span></span><br><span class="line"><span class="comment">         * &amp;drm_atomic_state to be able to track their own driver-private global</span></span><br><span class="line"><span class="comment">         * state easily. If this hook is implemented, drivers must also</span></span><br><span class="line"><span class="comment">         * implement @atomic_state_clear and @atomic_state_free.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Subclassing of &amp;drm_atomic_state is deprecated in favour of using</span></span><br><span class="line"><span class="comment">         * &amp;drm_private_state and &amp;drm_private_obj.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * RETURNS:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * A new &amp;drm_atomic_state on success or NULL on failure.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_atomic_state</span> *(*<span class="title">atomic_state_alloc</span>)(<span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>);</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @atomic_state_clear:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This hook must clear any driver private state duplicated into the</span></span><br><span class="line"><span class="comment">         * passed-in &amp;drm_atomic_state. This hook is called when the caller</span></span><br><span class="line"><span class="comment">         * encountered a &amp;drm_modeset_lock deadlock and needs to drop all</span></span><br><span class="line"><span class="comment">         * already acquired locks as part of the deadlock avoidance dance</span></span><br><span class="line"><span class="comment">         * implemented in drm_modeset_backoff().</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Any duplicated state must be invalidated since a concurrent atomic</span></span><br><span class="line"><span class="comment">         * update might change it, and the drm atomic interfaces always apply</span></span><br><span class="line"><span class="comment">         * updates as relative changes to the current state.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Drivers that implement this must call drm_atomic_state_default_clear()</span></span><br><span class="line"><span class="comment">         * to clear common state.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Subclassing of &amp;drm_atomic_state is deprecated in favour of using</span></span><br><span class="line"><span class="comment">         * &amp;drm_private_state and &amp;drm_private_obj.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*atomic_state_clear)(<span class="keyword">struct</span> drm_atomic_state *state);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @atomic_state_free:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This hook needs driver private resources and the &amp;drm_atomic_state</span></span><br><span class="line"><span class="comment">         * itself. Note that the core first calls drm_atomic_state_clear() to</span></span><br><span class="line"><span class="comment">         * avoid code duplicate between the clear and free hooks.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Drivers that implement this must call</span></span><br><span class="line"><span class="comment">         * drm_atomic_state_default_release() to release common resources.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Subclassing of &amp;drm_atomic_state is deprecated in favour of using</span></span><br><span class="line"><span class="comment">         * &amp;drm_private_state and &amp;drm_private_obj.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*atomic_state_free)(<span class="keyword">struct</span> drm_atomic_state *state);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

</details>

<p>其中：</p>
<ul>
<li><code>fb_create</code>：根据给定的帧缓冲参数，创建一个新的<code>framebuffer object</code>（并不是分配内存，只是创建<code>framebuffer object</code>，因为<code>framebuffer</code>不涉及内存的分配与释放），并返回其句柄；</li>
<li><code>get_format_info</code>：获取<code>DRM</code>格式信息，返回的数据类型为<code>struct drm_format_info</code>；</li>
</ul>
<h4 id="4-2-struct-drm-driver"><a href="#4-2-struct-drm-driver" class="headerlink" title="4.2  struct drm_driver"></a>4.2  <code>struct drm_driver</code></h4><p><code>linux</code>内核使用<code>struct drm_driver</code>数据结构来描述<code>drm</code>驱动，该数据结构是<code>drm</code>驱动的核心，<code>drm</code>驱动程序通常会静态初始化一个<code>drm_driver</code>结构体，其定义在<code>include/drm/drm_drv.h</code>：</p>
<details>
<summary>点击查看代码</summary>


<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct drm_driver - DRM driver structure</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure represent the common code for a family of cards. There will be</span></span><br><span class="line"><span class="comment"> * one &amp;struct drm_device for each card present in this family. It contains lots</span></span><br><span class="line"><span class="comment"> * of vfunc entries, and a pile of those probably should be moved to more</span></span><br><span class="line"><span class="comment"> * appropriate places like &amp;drm_mode_config_funcs or into a new operations</span></span><br><span class="line"><span class="comment"> * structure for GEM drivers.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_driver</span> &#123;</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @load:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Backward-compatible driver callback to complete initialization steps</span></span><br><span class="line"><span class="comment">         * after the driver is registered.  For this reason, may suffer from</span></span><br><span class="line"><span class="comment">         * race conditions and its use is deprecated for new drivers.  It is</span></span><br><span class="line"><span class="comment">         * therefore only supported for existing drivers not yet converted to</span></span><br><span class="line"><span class="comment">         * the new scheme.  See devm_drm_dev_alloc() and drm_dev_register() for</span></span><br><span class="line"><span class="comment">         * proper and race-free way to set up a &amp;struct drm_device.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is deprecated, do not use!</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Returns:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Zero on success, non-zero value on failure.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*load) (<span class="keyword">struct</span> drm_device *, <span class="type">unsigned</span> <span class="type">long</span> flags);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @open:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Driver callback when a new &amp;struct drm_file is opened. Useful for</span></span><br><span class="line"><span class="comment">         * setting up driver-private data structures like buffer allocators,</span></span><br><span class="line"><span class="comment">         * execution contexts or similar things. Such driver-private resources</span></span><br><span class="line"><span class="comment">         * must be released again in @postclose.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Since the display/modeset side of DRM can only be owned by exactly</span></span><br><span class="line"><span class="comment">         * one &amp;struct drm_file (see &amp;drm_file.is_master and &amp;drm_device.master)</span></span><br><span class="line"><span class="comment">         * there should never be a need to set up any modeset related resources</span></span><br><span class="line"><span class="comment">         * in this callback. Doing so would be a driver design bug.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Returns:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * 0 on success, a negative error code on failure, which will be</span></span><br><span class="line"><span class="comment">         * promoted to userspace as the result of the open() system call.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*open) (<span class="keyword">struct</span> drm_device *, <span class="keyword">struct</span> drm_file *);</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @postclose:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * One of the driver callbacks when a new &amp;struct drm_file is closed.</span></span><br><span class="line"><span class="comment">         * Useful for tearing down driver-private data structures allocated in</span></span><br><span class="line"><span class="comment">         * @open like buffer allocators, execution contexts or similar things.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Since the display/modeset side of DRM can only be owned by exactly</span></span><br><span class="line"><span class="comment">         * one &amp;struct drm_file (see &amp;drm_file.is_master and &amp;drm_device.master)</span></span><br><span class="line"><span class="comment">         * there should never be a need to tear down any modeset related</span></span><br><span class="line"><span class="comment">         * resources in this callback. Doing so would be a driver design bug.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*postclose) (<span class="keyword">struct</span> drm_device *, <span class="keyword">struct</span> drm_file *);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @lastclose:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Called when the last &amp;struct drm_file has been closed and there&#x27;s</span></span><br><span class="line"><span class="comment">         * currently no userspace client for the &amp;struct drm_device.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Modern drivers should only use this to force-restore the fbdev</span></span><br><span class="line"><span class="comment">         * framebuffer using drm_fb_helper_restore_fbdev_mode_unlocked().</span></span><br><span class="line"><span class="comment">         * Anything else would indicate there&#x27;s something seriously wrong.</span></span><br><span class="line"><span class="comment">         * Modern drivers can also use this to execute delayed power switching</span></span><br><span class="line"><span class="comment">         * state changes, e.g. in conjunction with the :ref:`vga_switcheroo`</span></span><br><span class="line"><span class="comment">         * infrastructure.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is called after @postclose hook has been called.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * <span class="doctag">NOTE:</span></span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * All legacy drivers use this callback to de-initialize the hardware.</span></span><br><span class="line"><span class="comment">         * This is purely because of the shadow-attach model, where the DRM</span></span><br><span class="line"><span class="comment">         * kernel driver does not really own the hardware. Instead ownershipe is</span></span><br><span class="line"><span class="comment">         * handled with the help of userspace through an inheritedly racy dance</span></span><br><span class="line"><span class="comment">         * to set/unset the VT into raw mode.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Legacy drivers initialize the hardware in the @firstopen callback,</span></span><br><span class="line"><span class="comment">         * which isn&#x27;t even called for modern drivers.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*lastclose) (<span class="keyword">struct</span> drm_device *);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @unload:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Reverse the effects of the driver load callback.  Ideally,</span></span><br><span class="line"><span class="comment">         * the clean up performed by the driver should happen in the</span></span><br><span class="line"><span class="comment">         * reverse order of the initialization.  Similarly to the load</span></span><br><span class="line"><span class="comment">         * hook, this handler is deprecated and its usage should be</span></span><br><span class="line"><span class="comment">         * dropped in favor of an open-coded teardown function at the</span></span><br><span class="line"><span class="comment">         * driver layer.  See drm_dev_unregister() and drm_dev_put()</span></span><br><span class="line"><span class="comment">         * for the proper way to remove a &amp;struct drm_device.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The unload() hook is called right after unregistering</span></span><br><span class="line"><span class="comment">         * the device.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*unload) (<span class="keyword">struct</span> drm_device *);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @release:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Optional callback for destroying device data after the final</span></span><br><span class="line"><span class="comment">         * reference is released, i.e. the device is being destroyed.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This is deprecated, clean up all memory allocations associated with a</span></span><br><span class="line"><span class="comment">         * &amp;drm_device using drmm_add_action(), drmm_kmalloc() and related</span></span><br><span class="line"><span class="comment">         * managed resources functions.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*release) (<span class="keyword">struct</span> drm_device *);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @master_set:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Called whenever the minor master is set. Only used by vmwgfx.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*master_set)(<span class="keyword">struct</span> drm_device *dev, <span class="keyword">struct</span> drm_file *file_priv,</span><br><span class="line">                           <span class="type">bool</span> from_open);</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @master_drop:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Called whenever the minor master is dropped. Only used by vmwgfx.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*master_drop)(<span class="keyword">struct</span> drm_device *dev, <span class="keyword">struct</span> drm_file *file_priv);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @debugfs_init:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Allows drivers to create driver-specific debugfs files.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">void</span> (*debugfs_init)(<span class="keyword">struct</span> drm_minor *minor);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @gem_create_object: constructor for gem objects</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Hook for allocating the GEM object struct, for use by the CMA</span></span><br><span class="line"><span class="comment">         * and SHMEM GEM helpers. Returns a GEM object on success, or an</span></span><br><span class="line"><span class="comment">         * ERR_PTR()-encoded error code otherwise.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *(*<span class="title">gem_create_object</span>)(<span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>,</span></span><br><span class="line"><span class="class">                                                    <span class="title">size_t</span> <span class="title">size</span>);</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @prime_handle_to_fd:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Main PRIME export function. Should be implemented with</span></span><br><span class="line"><span class="comment">         * drm_gem_prime_handle_to_fd() for GEM based drivers.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * For an in-depth discussion see :ref:`PRIME buffer sharing</span></span><br><span class="line"><span class="comment">         * documentation &lt;prime_buffer_sharing&gt;`.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*prime_handle_to_fd)(<span class="keyword">struct</span> drm_device *dev, <span class="keyword">struct</span> drm_file *file_priv,</span><br><span class="line">                                <span class="type">uint32_t</span> handle, <span class="type">uint32_t</span> flags, <span class="type">int</span> *prime_fd);</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @prime_fd_to_handle:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Main PRIME import function. Should be implemented with</span></span><br><span class="line"><span class="comment">         * drm_gem_prime_fd_to_handle() for GEM based drivers.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * For an in-depth discussion see :ref:`PRIME buffer sharing</span></span><br><span class="line"><span class="comment">         * documentation &lt;prime_buffer_sharing&gt;`.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*prime_fd_to_handle)(<span class="keyword">struct</span> drm_device *dev, <span class="keyword">struct</span> drm_file *file_priv,</span><br><span class="line">                                <span class="type">int</span> prime_fd, <span class="type">uint32_t</span> *handle);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @gem_prime_import:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Import hook for GEM drivers.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This defaults to drm_gem_prime_import() if not set.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> * (*<span class="title">gem_prime_import</span>)(<span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>,</span></span><br><span class="line"><span class="class">                                <span class="keyword">struct</span> <span class="title">dma_buf</span> *<span class="title">dma_buf</span>);</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @gem_prime_import_sg_table:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Optional hook used by the PRIME helper functions</span></span><br><span class="line"><span class="comment">         * drm_gem_prime_import() respectively drm_gem_prime_import_dev().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *(*<span class="title">gem_prime_import_sg_table</span>)(</span></span><br><span class="line"><span class="class">                                <span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>,</span></span><br><span class="line"><span class="class">                                <span class="keyword">struct</span> <span class="title">dma_buf_attachment</span> *<span class="title">attach</span>,</span></span><br><span class="line"><span class="class">                                <span class="keyword">struct</span> <span class="title">sg_table</span> *<span class="title">sgt</span>);</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @gem_prime_mmap:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * mmap hook for GEM drivers, used to implement dma-buf mmap in the</span></span><br><span class="line"><span class="comment">         * PRIME helpers.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This hook only exists for historical reasons. Drivers must use</span></span><br><span class="line"><span class="comment">         * drm_gem_prime_mmap() to implement it.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * <span class="doctag">FIXME:</span> Convert all drivers to implement mmap in struct</span></span><br><span class="line"><span class="comment">         * &amp;drm_gem_object_funcs and inline drm_gem_prime_mmap() into</span></span><br><span class="line"><span class="comment">         * its callers. This hook should be removed afterwards.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*gem_prime_mmap)(<span class="keyword">struct</span> drm_gem_object *obj, <span class="keyword">struct</span> vm_area_struct *vma);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dumb_create:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This creates a new dumb buffer in the driver&#x27;s backing storage manager (GEM,</span></span><br><span class="line"><span class="comment">         * TTM or something else entirely) and returns the resulting buffer handle. This</span></span><br><span class="line"><span class="comment">         * handle can then be wrapped up into a framebuffer modeset object.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Note that userspace is not allowed to use such objects for render</span></span><br><span class="line"><span class="comment">         * acceleration - drivers must create their own private ioctls for such a use</span></span><br><span class="line"><span class="comment">         * case.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Width, height and depth are specified in the &amp;drm_mode_create_dumb</span></span><br><span class="line"><span class="comment">         * argument. The callback needs to fill the handle, pitch and size for</span></span><br><span class="line"><span class="comment">         * the created buffer.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Called by the user via ioctl.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Returns:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Zero on success, negative errno on failure.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*dumb_create)(<span class="keyword">struct</span> drm_file *file_priv,</span><br><span class="line">                           <span class="keyword">struct</span> drm_device *dev,</span><br><span class="line">                           <span class="keyword">struct</span> drm_mode_create_dumb *args);</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dumb_map_offset:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Allocate an offset in the drm device node&#x27;s address space to be able to</span></span><br><span class="line"><span class="comment">         * memory map a dumb buffer.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The default implementation is drm_gem_create_mmap_offset(). GEM based</span></span><br><span class="line"><span class="comment">         * drivers must not overwrite this.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Called by the user via ioctl.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Returns:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Zero on success, negative errno on failure.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*dumb_map_offset)(<span class="keyword">struct</span> drm_file *file_priv,</span><br><span class="line">                               <span class="keyword">struct</span> drm_device *dev, <span class="type">uint32_t</span> handle,</span><br><span class="line">                               <span class="type">uint64_t</span> *offset);</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @dumb_destroy:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * This destroys the userspace handle for the given dumb backing storage buffer.</span></span><br><span class="line"><span class="comment">         * Since buffer objects must be reference counted in the kernel a buffer object</span></span><br><span class="line"><span class="comment">         * won&#x27;t be immediately freed if a framebuffer modeset object still uses it.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Called by the user via ioctl.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * The default implementation is drm_gem_dumb_destroy(). GEM based drivers</span></span><br><span class="line"><span class="comment">         * must not overwrite this.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Returns:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Zero on success, negative errno on failure.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> (*dumb_destroy)(<span class="keyword">struct</span> drm_file *file_priv,</span><br><span class="line">                            <span class="keyword">struct</span> drm_device *dev,</span><br><span class="line">                            <span class="type">uint32_t</span> handle);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/** @major: driver major number */</span></span><br><span class="line">        <span class="type">int</span> major;</span><br><span class="line">        <span class="comment">/** @minor: driver minor number */</span></span><br><span class="line">        <span class="type">int</span> minor;</span><br><span class="line">        <span class="comment">/** @patchlevel: driver patch level */</span></span><br><span class="line">        <span class="type">int</span> patchlevel;</span><br><span class="line">        <span class="comment">/** @name: driver name */</span></span><br><span class="line">        <span class="type">char</span> *name;</span><br><span class="line">        <span class="comment">/** @desc: driver description */</span></span><br><span class="line">        <span class="type">char</span> *desc;</span><br><span class="line">        <span class="comment">/** @date: driver date */</span></span><br><span class="line">        <span class="type">char</span> *date;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @driver_features:</span></span><br><span class="line"><span class="comment">         * Driver features, see &amp;enum drm_driver_feature. Drivers can disable</span></span><br><span class="line"><span class="comment">         * some features on a per-instance basis using</span></span><br><span class="line"><span class="comment">         * &amp;drm_device.driver_features.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        u32 driver_features;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @ioctls:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Array of driver-private IOCTL description entries. See the chapter on</span></span><br><span class="line"><span class="comment">         * :ref:`IOCTL support in the userland interfaces</span></span><br><span class="line"><span class="comment">         * chapter&lt;drm_driver_ioctl&gt;` for the full details.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line"></span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_ioctl_desc</span> *<span class="title">ioctls</span>;</span></span><br><span class="line">        <span class="comment">/** @num_ioctls: Number of entries in @ioctls. */</span></span><br><span class="line">        <span class="type">int</span> num_ioctls;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * @fops:</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * File operations for the DRM device node. See the discussion in</span></span><br><span class="line"><span class="comment">         * :ref:`file operations&lt;drm_driver_fops&gt;` for in-depth coverage and</span></span><br><span class="line"><span class="comment">         * some examples.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> *<span class="title">fops</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> CONFIG_DRM_LEGACY</span></span><br><span class="line">        <span class="comment">/* Everything below here is for legacy driver, never use! */</span></span><br><span class="line">        <span class="comment">/* private: */</span></span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> (*firstopen) (<span class="keyword">struct</span> drm_device *);</span><br><span class="line">        <span class="type">void</span> (*preclose) (<span class="keyword">struct</span> drm_device *, <span class="keyword">struct</span> drm_file *file_priv);</span><br><span class="line">        <span class="type">int</span> (*dma_ioctl) (<span class="keyword">struct</span> drm_device *dev, <span class="type">void</span> *data, <span class="keyword">struct</span> drm_file *file_priv);</span><br><span class="line">        <span class="type">int</span> (*dma_quiescent) (<span class="keyword">struct</span> drm_device *);</span><br><span class="line">        <span class="type">int</span> (*context_dtor) (<span class="keyword">struct</span> drm_device *dev, <span class="type">int</span> context);</span><br><span class="line">        <span class="type">irqreturn_t</span> (*irq_handler)(<span class="type">int</span> irq, <span class="type">void</span> *arg);</span><br><span class="line">        <span class="type">void</span> (*irq_preinstall)(<span class="keyword">struct</span> drm_device *dev);</span><br><span class="line">        <span class="type">int</span> (*irq_postinstall)(<span class="keyword">struct</span> drm_device *dev);</span><br><span class="line">        <span class="type">void</span> (*irq_uninstall)(<span class="keyword">struct</span> drm_device *dev);</span><br><span class="line">        u32 (*get_vblank_counter)(<span class="keyword">struct</span> drm_device *dev, <span class="type">unsigned</span> <span class="type">int</span> pipe);</span><br><span class="line">        <span class="type">int</span> (*enable_vblank)(<span class="keyword">struct</span> drm_device *dev, <span class="type">unsigned</span> <span class="type">int</span> pipe);</span><br><span class="line">        <span class="type">void</span> (*disable_vblank)(<span class="keyword">struct</span> drm_device *dev, <span class="type">unsigned</span> <span class="type">int</span> pipe);</span><br><span class="line">        <span class="type">int</span> dev_priv_size;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

</details>

<p>同样，该数据结构也包含了大量的成员，其中：</p>
<ul>
<li><code>prime_handle_to_fd</code>：主要的<code>PRIME</code>导出函数，对于基于<code>GEM</code>的驱动程序，应使用<code>drm_gem_prime_handle_to_fd</code>实现它，有关详细讨论，请参阅<a target="_blank" rel="noopener" href="https://docs.kernel.org/gpu/drm-mm.html#prime-buffer-sharing"><code>PRIME buffer sharing documentation</code></a>；</li>
<li><code>prime_fd_to_handle</code>：主要的<code>PRIME</code>导入函数，对于基于GEM的驱动程序，应使用<code>drm_gem_prime_fd_to_handle</code>实现它，，有关详细讨论，请参阅<a target="_blank" rel="noopener" href="https://docs.kernel.org/gpu/drm-mm.html#prime-buffer-sharing"><code>PRIME buffer sharing documentation</code></a>；</li>
<li><code>gem_prime_import_sg_table</code>：是<code>PRIME helpers</code>函数<code>drm_gem_prime_import</code>和<code>drm_gem_prime_import_dev</code>使用的可选钩子；</li>
<li><code>gem_prime_mmap</code>：用于在<code>GEM</code>驱动程序中实现<code>PRIME helpers</code>的<code>dma-buf mmap</code>的<code>mmap</code>钩子，这个钩子只是出于历史原因而存在，驱动程序必须使用<code>drm_gem_prime_mmap</code>来实现它；</li>
<li><code>name</code>：驱动名称；</li>
<li><code>desc</code>：驱动的描述信息；</li>
<li><code>date</code>：驱动的日期以<code>YYYYMMDD</code>的格式表示，用于标识驱动程序的最新修改日期。然而，由于大多数驱动程序未及时更新它，所以它的值大多没有实际意义；</li>
<li><code>major</code>：主版本号；</li>
<li><code>minor</code>：次版本号；</li>
<li><code>patchlevel</code>：补丁版本号；</li>
<li><code>data</code>：驱动数据；</li>
<li><code>driver_features</code>：一个标志位集合，用于指定在该驱动程序实例中允许的特定功能；比如：<ul>
<li>添加上 <code>DRIVER_MODESET</code>标志位，告诉<code>DRM Core</code>当前驱动支持<code>kernel Mode Setting</code>操作；</li>
<li>添加上<code>DRIVER_GEM</code>标志位，告诉<code>DRM Core</code>该驱动支持<code>GEM</code>操作；</li>
<li>添加上 <code>DRIVER_ATOMIC</code> 标志位，告诉<code>DRM Core</code>该驱动支持<code>Atomic</code>操作。</li>
</ul>
</li>
<li><code>fops</code>：<code>DRM</code>设备节点文件操作集，比如我们对设备节点<code>/dev/dri/card0</code>进行读写，就会调用相应的操作方法；</li>
<li><code>dumb_create</code>：该函数用于在驱动程序的后备存储管理器（如 <code>GEM、TTM</code>或其他管理器）中创建一个新的 <code>dumb buffer</code>，并返回相应的缓冲区句柄；这个句柄可以用来创建一个<code>framebuffer modeset</code>对象；</li>
</ul>
<h5 id="4-2-1-driver-feature"><a href="#4-2-1-driver-feature" class="headerlink" title="4.2.1 driver_feature"></a>4.2.1 <code>driver_feature</code></h5><p><code>drm</code>驱动特征使用可以使用如下标识位：</p>
<ul>
<li><code>DRIVER_GEM</code>：驱动程序使用<code>GEM</code>内存管理器，这对于所有现代驱动程序都应该设置；</li>
<li><code>DRIVER_MODESET</code>：驱动程序支持模式设置接口（<code>KMS</code>）；</li>
<li><code>DRIVER_RENDER</code>：Driver supports dedicated render nodes. See also the section on render nodes for details.</li>
<li><code>DRIVER_ATOMIC</code>：Driver supports the full atomic modesetting userspace API. Drivers which only use atomic internally, but do not support the full userspace API (e.g. not all properties converted to atomic, or multi-plane updates are not guaranteed to be tear-free) should not set this flag.</li>
<li><code>DRIVER_SYNCOB</code>：Driver supports drm_syncobj for explicit synchronization of command submission.</li>
<li><code>DRIVER_SYNCOBJ_TIMELINE</code>：Driver supports the timeline flavor of drm_syncobj for explicit synchronization of command submission.</li>
<li><code>DRIVER_COMPUTE_ACCEL</code>：Driver supports compute acceleration devices. This flag is mutually exclusive with DRIVER_RENDER and DRIVER_MODESET. Devices that support both graphics and compute acceleration should be handled by two drivers that are connected using auxiliary bus.</li>
<li><code>DRIVER_USE_AGP</code>：Set up DRM AGP support, see drm_agp_init(), the DRM core will manage AGP resources. New drivers don’t need this.</li>
<li><code>DRIVER_LEGACY</code>：Denote a legacy driver using shadow attach. Do not use.</li>
<li><code>DRIVER_PCI_DMA</code>：Driver is capable of PCI DMA, mapping of PCI DMA buffers to userspace will be enabled. Only for legacy drivers. Do not use.</li>
<li><code>DRIVER_SG</code>：Driver can perform scatter&#x2F;gather DMA, allocation and mapping of scatter&#x2F;gather buffers will be enabled. Only for legacy drivers. Do not use.</li>
<li><code>DRIVER_HAVE_DMA</code>：Driver supports DMA, the userspace DMA API will be supported. Only for legacy drivers. Do not use.</li>
<li><code>DRIVER_HAVE_IRQ</code>：Legacy irq support. Only for legacy drivers. Do not use.</li>
</ul>
<h5 id="4-2-2-dumb-create"><a href="#4-2-2-dumb-create" class="headerlink" title="4.2.2 dumb_create"></a>4.2.2 <code>dumb_create</code></h5><p><code>dumb_create</code>是分配物理内存<code>dumb buffer</code>的回调接口；那什么是<code>dumb buffer</code>呢？</p>
<p><code>dumb buffer</code>代表了所有的绘图操作都由<code>CPU</code>来完成的<code>framebuffer</code>，更多细节可以参考文章<a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/article/details/105961192">《关于<code>DRM</code>中<code>DUMB</code>和<code>PRIME</code>名字的由来》</a>。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> (*dumb_create)(<span class="keyword">struct</span> drm_file *file_priv,</span><br><span class="line">                   <span class="keyword">struct</span> drm_device *dev,</span><br><span class="line">                   <span class="keyword">struct</span> drm_mode_create_dumb *args);</span><br></pre></td></tr></table></figure>
<p>在<code>drm_mode_create_dumb</code>参数中指定了<code>width</code>、<code>height</code>和<code>bpp</code>，<code>dumb_create</code>函数需要为创建的<code>dumb buffer</code>填充<code>handle</code>、<code>pitch</code>和<code>size</code>，该回调函数是通过<code>ioctl</code>由用户调用的。</p>
<p>主要完成三件事：</p>
<ul>
<li>创建<code>gem objec</code>;</li>
<li>创建<code>gem handle</code>;</li>
<li>分配物理内存<code>dumb buffer</code>（可选的） ；</li>
</ul>
<p>第1、第2 步是所有<code>dumb_create</code>都必须实现的操作，而第3步则是可选的，对于一次性映射需要事先分配好所有的物理内存。</p>
<p>分配完物理内存后，就可以通过<code>mmap</code>将分配好的物理内存映射到用户空间。</p>
<h5 id="4-2-3-struct-drm-file"><a href="#4-2-3-struct-drm-file" class="headerlink" title="4.2.3 struct drm_file"></a>4.2.3 <code>struct drm_file</code></h5><p><code>DRM</code>文件私有数据是驱动程序在处理文件操作时使用的附加数据，在<code>DRM</code>中每个打开的文件都与一个<code>struct drm_file</code>实例关联：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">drm_file</span> &#123;</span></span><br><span class="line">    <span class="type">bool</span> authenticated;</span><br><span class="line">    <span class="type">bool</span> stereo_allowed;</span><br><span class="line">    <span class="type">bool</span> universal_planes;</span><br><span class="line">    <span class="type">bool</span> atomic;</span><br><span class="line">    <span class="type">bool</span> aspect_ratio_allowed;</span><br><span class="line">    <span class="type">bool</span> writeback_connectors;</span><br><span class="line">    <span class="type">bool</span> was_master;</span><br><span class="line">    <span class="type">bool</span> is_master;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">drm_master</span> *<span class="title">master</span>;</span></span><br><span class="line">    <span class="type">spinlock_t</span> master_lookup_lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">pid</span> *<span class="title">pid</span>;</span></span><br><span class="line">    u64 client_id;</span><br><span class="line">    <span class="type">drm_magic_t</span> magic;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">lhead</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">minor</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">idr</span> <span class="title">object_idr</span>;</span></span><br><span class="line">    <span class="type">spinlock_t</span> table_lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">idr</span> <span class="title">syncobj_idr</span>;</span></span><br><span class="line">    <span class="type">spinlock_t</span> syncobj_table_lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">filp</span>;</span></span><br><span class="line">    <span class="type">void</span> *driver_priv;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">fbs</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">fbs_lock</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">blobs</span>;</span></span><br><span class="line">    <span class="type">wait_queue_head_t</span> event_wait;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">pending_event_list</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">event_list</span>;</span></span><br><span class="line">    <span class="type">int</span> event_space;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">event_read_lock</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">drm_prime_file_private</span> <span class="title">prime</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h3 id="五、DRM-core模块入口"><a href="#五、DRM-core模块入口" class="headerlink" title="五、DRM core模块入口"></a>五、<code>DRM core</code>模块入口</h3><p><code>DRM core</code>模块入口函数为<code>drm_core_init</code>，位于<code>drivers/gpu/drm/drm_drv.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">drm_core_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        drm_connector_ida_init();</span><br><span class="line">        <span class="comment">// IDR初始化</span></span><br><span class="line">        idr_init(&amp;drm_minors_idr);</span><br><span class="line">        drm_memcpy_init_early();</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 创建class类drm_class，同时会在/sys/class/目录下创建一个新的文件夹drm</span></span><br><span class="line">        ret = drm_sysfs_init();</span><br><span class="line">        <span class="keyword">if</span> (ret &lt; <span class="number">0</span>) &#123;</span><br><span class="line">                DRM_ERROR(<span class="string">&quot;Cannot create DRM class: %d\n&quot;</span>, ret);</span><br><span class="line">                <span class="keyword">goto</span> error;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">//  在/sys/kernel/debug下创建dri目录</span></span><br><span class="line">        drm_debugfs_root = debugfs_create_dir(<span class="string">&quot;dri&quot;</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 申请主设备号，同时初始化以及注册字符设备cdev（这里注册的字符设备数量为256），并将字符设备的ops和drm_stub_fops绑定在一起</span></span><br><span class="line">        ret = register_chrdev(DRM_MAJOR, <span class="string">&quot;drm&quot;</span>, &amp;drm_stub_fops);</span><br><span class="line">        <span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">goto</span> error;</span><br><span class="line"></span><br><span class="line">        ret = accel_core_init();</span><br><span class="line">        <span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">goto</span> error;</span><br><span class="line"></span><br><span class="line">        drm_privacy_screen_lookup_init();</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 设置标志位</span></span><br><span class="line">        drm_core_init_complete = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">        DRM_DEBUG(<span class="string">&quot;Initialized\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">error:</span><br><span class="line">        drm_core_exit();</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(drm_core_init);</span><br></pre></td></tr></table></figure>

<p>在<code>DRM core</code>初始化函数中，主要进行了如下操作：</p>
<ul>
<li>调用<code>drm_sysfs_init</code>创建<code>class</code>类<code>drm_class</code>，在<code>/sys/class</code>目录下一个名称为<code>drm</code>的文件夹；</li>
<li>调用<code>debugfs_create_dir</code>在<code>/sys/kernel/debug</code>下创建<code>dri</code>目录；</li>
<li>调用<code>register_chrdev</code>申请主设备号为<code>DRM_MAJOR</code>（值为226），同时注册256个字符设备，并将字符设备的<code>ops</code>和<code>drm_stub_fops</code>绑定在一起；</li>
</ul>
<h4 id="5-1-drm-sysfs-init"><a href="#5-1-drm-sysfs-init" class="headerlink" title="5.1 drm_sysfs_init"></a>5.1 <code>drm_sysfs_init</code></h4><p><code>drm_sysfs_init</code>定义在<code>drivers/gpu/drm/drm_sysfs.c</code>，用于创建一个<code>DRM class</code>类；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_sysfs_init - initialize sysfs helpers</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This is used to create the DRM class, which is the implicit parent of any</span></span><br><span class="line"><span class="comment"> * other top-level DRM sysfs objects.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * You must call drm_sysfs_destroy() to release the allocated resources.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Return: 0 on success, negative error code on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drm_sysfs_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 创建设备类，此函数的执行会在/sys/class/目录下创建一个新的文件夹drm</span></span><br><span class="line">        drm_class = class_create(THIS_MODULE, <span class="string">&quot;drm&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(drm_class))</span><br><span class="line">                <span class="keyword">return</span> PTR_ERR(drm_class);</span><br><span class="line"></span><br><span class="line">        err = class_create_file(drm_class, &amp;class_attr_version.attr);</span><br><span class="line">        <span class="keyword">if</span> (err) &#123;</span><br><span class="line">                class_destroy(drm_class);</span><br><span class="line">                drm_class = <span class="literal">NULL</span>;</span><br><span class="line">                <span class="keyword">return</span> err;</span><br><span class="line">        &#125;</span><br><span class="line">		</span><br><span class="line">        <span class="comment">// 设置设备节点</span></span><br><span class="line">        drm_class-&gt;devnode = drm_devnode;</span><br><span class="line"></span><br><span class="line">        drm_sysfs_acpi_register();</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到在<code>drm_sysfs_init</code>函数中创建了<code>class</code>类<code>drm_class</code>，名称为<code>drm</code>，并设置<code>devnode</code>指向了<code>drm_devnode</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">char</span> *<span class="title function_">drm_devnode</span><span class="params">(<span class="type">const</span> <span class="keyword">struct</span> device *dev, <span class="type">umode_t</span> *mode)</span></span><br><span class="line">&#123;</span><br><span class="line">    	<span class="comment">// 设置dev下设备节点名称  /dev/dri/xxx</span></span><br><span class="line">        <span class="keyword">return</span> kasprintf(GFP_KERNEL, <span class="string">&quot;dri/%s&quot;</span>, dev_name(dev));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>那么<code>udev</code>就会根据<code>devnode</code>的返回值来决定创建的设备节点文件的相对路径。同时，<code>udev</code>还会为这些设备节点文件设置相应的权限、所属用户和组等信息，以确保用户可以正确访问这些设备节点文件。</p>
<p>比如，在<code>NanoPC-T4</code>开发板运行如下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">root@rk3399:~# ll /sys/class/drm</span><br><span class="line">lrwxrwxrwx  1 root root    0 Mar 15 23:04 card0 -&gt; ../../devices/platform/display-subsystem/drm/card0/</span><br><span class="line">lrwxrwxrwx  1 root root    0 Mar 15 23:04 card0-HDMI-A-1 -&gt; ../../devices/platform/display-subsystem/drm/card0/card0-HDMI-A-1/</span><br><span class="line">lrwxrwxrwx  1 root root    0 Mar 15 23:04 card1 -&gt; ../../devices/platform/ff9a0000.gpu/drm/card1/</span><br><span class="line">lrwxrwxrwx  1 root root    0 Mar 15 23:04 renderD128 -&gt; ../../devices/platform/ff9a0000.gpu/drm/renderD128/</span><br><span class="line">-r--r--r--  1 root root 4096 Mar 15 23:04 version</span><br></pre></td></tr></table></figure>

<h4 id="5-2-drm-stub-fops"><a href="#5-2-drm-stub-fops" class="headerlink" title="5.2 drm_stub_fops"></a>5.2 <code>drm_stub_fops</code></h4><p>字符设备文件操作集被设置为了<code>drm_stub_fops</code>，其定义在<code>drivers/gpu/drm/drm_drv.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * DRM Core</span></span><br><span class="line"><span class="comment"> * The DRM core module initializes all global DRM objects and makes them</span></span><br><span class="line"><span class="comment"> * available to drivers. Once setup, drivers can probe their respective</span></span><br><span class="line"><span class="comment"> * devices.</span></span><br><span class="line"><span class="comment"> * Currently, core management includes:</span></span><br><span class="line"><span class="comment"> *  - The &quot;DRM-Global&quot; key/value database</span></span><br><span class="line"><span class="comment"> *  - Global ID management for connectors</span></span><br><span class="line"><span class="comment"> *  - DRM major number allocation</span></span><br><span class="line"><span class="comment"> *  - DRM minor management</span></span><br><span class="line"><span class="comment"> *  - DRM sysfs class</span></span><br><span class="line"><span class="comment"> *  - DRM debugfs root</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Furthermore, the DRM core provides dynamic char-dev lookups. For each</span></span><br><span class="line"><span class="comment"> * interface registered on a DRM device, you can request minor numbers from DRM</span></span><br><span class="line"><span class="comment"> * core. DRM core takes care of major-number management and char-dev</span></span><br><span class="line"><span class="comment"> * registration. A stub -&gt;open() callback forwards any open() requests to the</span></span><br><span class="line"><span class="comment"> * registered minor.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_stub_open</span><span class="params">(<span class="keyword">struct</span> inode *inode, <span class="keyword">struct</span> file *filp)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> *<span class="title">new_fops</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">minor</span>;</span></span><br><span class="line">        <span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">        DRM_DEBUG(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 根据设备节点获取struct drm_minor</span></span><br><span class="line">        minor = drm_minor_acquire(iminor(inode));</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(minor))</span><br><span class="line">                <span class="keyword">return</span> PTR_ERR(minor);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 获取drm driver的文件操作集</span></span><br><span class="line">        new_fops = fops_get(minor-&gt;dev-&gt;driver-&gt;fops);</span><br><span class="line">        <span class="keyword">if</span> (!new_fops) &#123;</span><br><span class="line">                err = -ENODEV;</span><br><span class="line">                <span class="keyword">goto</span> out;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 用new_fops替换file-&gt;f_op</span></span><br><span class="line">        replace_fops(filp, new_fops);</span><br><span class="line">    </span><br><span class="line">	    <span class="comment">// 执行设备的文件open函数</span></span><br><span class="line">        <span class="keyword">if</span> (filp-&gt;f_op-&gt;open)</span><br><span class="line">                err = filp-&gt;f_op-&gt;open(inode, filp);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">                err = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">out:</span><br><span class="line">        drm_minor_release(minor);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">drm_stub_fops</span> =</span> &#123;</span><br><span class="line">        .owner = THIS_MODULE,</span><br><span class="line">        .open = drm_stub_open,</span><br><span class="line">        .llseek = noop_llseek,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>当上层应用打开<code>drm</code>设备时，通过<code>drm</code>设备节点获取到<code>drm_minor</code>。通过对文件指针进行重定向，打开真正的<code>drm</code>设备的<code>open</code>函数。</p>
<h3 id="六、初始化drm设备"><a href="#六、初始化drm设备" class="headerlink" title="六、初始化drm设备"></a>六、初始化<code>drm</code>设备</h3><p><code>drm_dev_init</code>函数用于初始化<code>struct drm_device</code>实例，函数定义在<code>drivers/gpu/drm/drm_drv.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_dev_init</span><span class="params">(<span class="keyword">struct</span> drm_device *dev,</span></span><br><span class="line"><span class="params">                        <span class="type">const</span> <span class="keyword">struct</span> drm_driver *driver,</span></span><br><span class="line"><span class="params">                        <span class="keyword">struct</span> device *parent)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">inode</span> *<span class="title">inode</span>;</span></span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!drm_core_init_complete) &#123;</span><br><span class="line">                DRM_ERROR(<span class="string">&quot;DRM core is not initialized\n&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> -ENODEV;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (WARN_ON(!parent))</span><br><span class="line">                <span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化drm_device对象引用计数为1</span></span><br><span class="line">        kref_init(&amp;dev-&gt;ref);</span><br><span class="line">        dev-&gt;dev = get_device(parent);</span><br><span class="line">        dev-&gt;driver = driver;</span><br><span class="line"></span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;managed.resources);</span><br><span class="line">        spin_lock_init(&amp;dev-&gt;managed.lock);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* no per-device feature limits by default */</span></span><br><span class="line">        dev-&gt;driver_features = ~<span class="number">0u</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL) &amp;&amp;</span><br><span class="line">                                (drm_core_check_feature(dev, DRIVER_RENDER) ||</span><br><span class="line">                                drm_core_check_feature(dev, DRIVER_MODESET))) &#123;</span><br><span class="line">                DRM_ERROR(<span class="string">&quot;DRM driver can&#x27;t be both a compute acceleration and graphics driver\n&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> -EINVAL;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        drm_legacy_init_members(dev);</span><br><span class="line">    	<span class="comment">// 初始化各种链表头节点</span></span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;filelist);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;filelist_internal);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;clientlist);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;vblank_event_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;debugfs_list);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化各种锁</span></span><br><span class="line">        spin_lock_init(&amp;dev-&gt;event_lock);</span><br><span class="line">        mutex_init(&amp;dev-&gt;struct_mutex);</span><br><span class="line">        mutex_init(&amp;dev-&gt;filelist_mutex);</span><br><span class="line">        mutex_init(&amp;dev-&gt;clientlist_mutex);</span><br><span class="line">        mutex_init(&amp;dev-&gt;master_mutex);</span><br><span class="line">        mutex_init(&amp;dev-&gt;debugfs_mutex);</span><br><span class="line"></span><br><span class="line">        ret = drmm_add_action_or_reset(dev, drm_dev_init_release, <span class="literal">NULL</span>);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">return</span> ret;</span><br><span class="line">        inode = drm_fs_inode_new();</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(inode)) &#123;</span><br><span class="line">                ret = PTR_ERR(inode);</span><br><span class="line">                DRM_ERROR(<span class="string">&quot;Cannot allocate anonymous inode: %d\n&quot;</span>, ret);</span><br><span class="line">                <span class="keyword">goto</span> err;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        dev-&gt;anon_inode = inode;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 如果driver_feature设置了DRIVER_COMPUTE_ACCEL，不会进入</span></span><br><span class="line">        <span class="keyword">if</span> (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) &#123;</span><br><span class="line">                ret = drm_minor_alloc(dev, DRM_MINOR_ACCEL);</span><br><span class="line">                <span class="keyword">if</span> (ret)</span><br><span class="line">                        <span class="keyword">goto</span> err;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123; <span class="comment">// 如果driver_feature设置了DRIVER_RENDER，不会进入</span></span><br><span class="line">                <span class="keyword">if</span> (drm_core_check_feature(dev, DRIVER_RENDER)) &#123;</span><br><span class="line">                        ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);</span><br><span class="line">                        <span class="keyword">if</span> (ret)</span><br><span class="line">                                <span class="keyword">goto</span> err;</span><br><span class="line">                &#125;</span><br><span class="line">				<span class="comment">// 正常走这里</span></span><br><span class="line">                ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);</span><br><span class="line">                <span class="keyword">if</span> (ret)</span><br><span class="line">                        <span class="keyword">goto</span> err;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        ret = drm_legacy_create_map_hash(dev);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err;</span><br><span class="line"></span><br><span class="line">        drm_legacy_ctxbitmap_init(dev);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 如果driver_feature设置了DRIVER_GEM，会进入</span></span><br><span class="line">        <span class="keyword">if</span> (drm_core_check_feature(dev, DRIVER_GEM)) &#123;</span><br><span class="line">                ret = drm_gem_init(dev);</span><br><span class="line">                <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                        DRM_ERROR(<span class="string">&quot;Cannot initialize graphics execution manager (GEM)\n&quot;</span>);</span><br><span class="line">                        <span class="keyword">goto</span> err;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化dev-&gt;unique</span></span><br><span class="line">        ret = drm_dev_set_unique(dev, dev_name(parent));</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err:</span><br><span class="line">        drm_managed_release(dev);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里咱们以<code>RK3399</code> <code>DRM</code>驱动为例，</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_driver</span> <span class="title">rockchip_drm_driver</span> =</span> &#123;</span><br><span class="line">        .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,</span><br><span class="line">        ....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>由于<code>driver_features</code>并没有设定<code>DRIVER_COMPUTE_ACCEL</code>、<code>DRM_MINOR_PRIMARY</code>，因此并不会执行如下代码：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ret = drm_minor_alloc(dev, DRM_MINOR_ACCEL);</span><br><span class="line">ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);</span><br></pre></td></tr></table></figure>

<p>故而不会初始化<code>drm_device</code>成员<code>render</code>、<code>accel</code>。</p>
<p><code>drm_dev_init</code>函数中会执行以下两个比较重要的步骤，下面我们依次介绍。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 初始化dev-&gt;primary</span></span><br><span class="line">ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);</span><br><span class="line">...</span><br><span class="line">ret = drm_gem_init(dev);</span><br></pre></td></tr></table></figure>

<h4 id="6-1-drm-minor-alloc"><a href="#6-1-drm-minor-alloc" class="headerlink" title="6.1 drm_minor_alloc"></a>6.1 <code>drm_minor_alloc</code></h4><p><code>drm_minor_alloc</code>定义在<code>drivers/gpu/drm/drm_drv.c</code>，用以动态分配一个<code>struct drm_minor</code>，然后动态分配和初始化<code>drm_minor</code>-&gt;<code>kdev</code>，其最终目的是为了注册字符设备并创建设备节点<code>/dev/dri/card%d</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_minor_alloc</span><span class="params">(<span class="keyword">struct</span> drm_device *dev, <span class="type">unsigned</span> <span class="type">int</span> type)</span> <span class="comment">// type传入DRM_MINOR_PRIMARY=0</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">minor</span>;</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> flags;</span><br><span class="line">        <span class="type">int</span> r;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 动态分配struct drm_minor</span></span><br><span class="line">        minor = drmm_kzalloc(dev, <span class="keyword">sizeof</span>(*minor), GFP_KERNEL);</span><br><span class="line">        <span class="keyword">if</span> (!minor)</span><br><span class="line">                <span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line">        minor-&gt;type = type;</span><br><span class="line">        minor-&gt;dev = dev;</span><br><span class="line"></span><br><span class="line">        idr_preload(GFP_KERNEL);</span><br><span class="line">        <span class="keyword">if</span> (type == DRM_MINOR_ACCEL) &#123;  <span class="comment">// 不会进入</span></span><br><span class="line">                r = accel_minor_alloc();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">	            <span class="comment">// 获取自旋锁+关中断</span></span><br><span class="line">                spin_lock_irqsave(&amp;drm_minor_lock, flags);</span><br><span class="line">            	<span class="comment">// 基于基数树分配唯一id  区间位于64 * type~64 * (type + 1)；由于tye=0，所以次设备编号为0~1；</span></span><br><span class="line">                r = idr_alloc(&amp;drm_minors_idr,</span><br><span class="line">                        <span class="literal">NULL</span>,</span><br><span class="line">                        <span class="number">64</span> * type,</span><br><span class="line">                        <span class="number">64</span> * (type + <span class="number">1</span>),</span><br><span class="line">                        GFP_NOWAIT);</span><br><span class="line">	            <span class="comment">// 释放自旋锁+开中断</span></span><br><span class="line">                spin_unlock_irqrestore(&amp;drm_minor_lock, flags);</span><br><span class="line">        &#125;</span><br><span class="line">        idr_preload_end();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (r &lt; <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">return</span> r;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 设置次设备编号</span></span><br><span class="line">        minor-&gt;index = r;</span><br><span class="line"></span><br><span class="line">        r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);</span><br><span class="line">        <span class="keyword">if</span> (r)</span><br><span class="line">                <span class="keyword">return</span> r;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 为minor分配并初始化一个struct device</span></span><br><span class="line">        minor-&gt;kdev = drm_sysfs_minor_alloc(minor);</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(minor-&gt;kdev))</span><br><span class="line">                <span class="keyword">return</span> PTR_ERR(minor-&gt;kdev);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化dev-&gt;primary=minor</span></span><br><span class="line">        *drm_minor_get_slot(dev, type) = minor;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="6-1-1-drm-sysfs-minor-alloc"><a href="#6-1-1-drm-sysfs-minor-alloc" class="headerlink" title="6.1.1  drm_sysfs_minor_alloc"></a>6.1.1  <code>drm_sysfs_minor_alloc</code></h5><p><code>drm_sysfs_minor_alloc</code>函数实际上主要就是为<code>minor</code>分配并初始化一个<code>struct device</code>，定义在<code>drivers/gpu/drm/drm_sysfs.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> device *<span class="title function_">drm_sysfs_minor_alloc</span><span class="params">(<span class="keyword">struct</span> drm_minor *minor)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">const</span> <span class="type">char</span> *minor_str;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">kdev</span>;</span></span><br><span class="line">        <span class="type">int</span> r;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 动态初始化struct device</span></span><br><span class="line">        kdev = kzalloc(<span class="keyword">sizeof</span>(*kdev), GFP_KERNEL);</span><br><span class="line">        <span class="keyword">if</span> (!kdev)</span><br><span class="line">                <span class="keyword">return</span> ERR_PTR(-ENOMEM);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化设备，这个函数是device_register函数的前半部分的实现，主要用于设备的初始化</span></span><br><span class="line">        device_initialize(kdev);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (minor-&gt;type == DRM_MINOR_ACCEL) &#123; <span class="comment">// 不会进入</span></span><br><span class="line">                minor_str = <span class="string">&quot;accel%d&quot;</span>;</span><br><span class="line">                accel_set_device_instance_params(kdev, minor-&gt;index);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (minor-&gt;type == DRM_MINOR_RENDER)</span><br><span class="line">                        minor_str = <span class="string">&quot;renderD%d&quot;</span>;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                        minor_str = <span class="string">&quot;card%d&quot;</span>;  <span class="comment">// 走这里</span></span><br><span class="line"></span><br><span class="line">            	<span class="comment">// 设置设备号 主设备号为226，次设备号为minor-&gt;index</span></span><br><span class="line">                kdev-&gt;devt = MKDEV(DRM_MAJOR, minor-&gt;index);</span><br><span class="line">            	<span class="comment">// 设置设备class</span></span><br><span class="line">                kdev-&gt;<span class="class"><span class="keyword">class</span> =</span> drm_class;</span><br><span class="line">            	<span class="comment">// 设备类型</span></span><br><span class="line">                kdev-&gt;type = &amp;drm_sysfs_device_minor;</span><br><span class="line">        &#125;</span><br><span class="line">		<span class="comment">// 设置父设备</span></span><br><span class="line">        kdev-&gt;parent = minor-&gt;dev-&gt;dev;</span><br><span class="line">        kdev-&gt;release = drm_sysfs_release;</span><br><span class="line">    </span><br><span class="line">	    <span class="comment">// 设置设备驱动数据为minor</span></span><br><span class="line">        dev_set_drvdata(kdev, minor);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 设置设备名称为 card%d</span></span><br><span class="line">        r = dev_set_name(kdev, minor_str, minor-&gt;index);</span><br><span class="line">        <span class="keyword">if</span> (r &lt; <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">goto</span> err_free;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> kdev;</span><br><span class="line"></span><br><span class="line">err_free:</span><br><span class="line">        put_device(kdev);</span><br><span class="line">        <span class="keyword">return</span> ERR_PTR(r);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>具体流程如下：</p>
<ul>
<li><p>动态分配一个<code>struct device</code>；</p>
</li>
<li><p>调用<code>device_initialize</code>初始化设备，这个函数是<code>device_register</code>函数的前半部分的实现，主要用于设备的初始化；</p>
<ul>
<li>而<code>device_add</code>是在<code>drm_minor_register</code>函数中调用，该函数执行完会在<code>/sys/class/drm</code>创建<code>card%d</code>文件，同时创建设备节点<code>/dev/drm/card%d</code>；</li>
</ul>
</li>
<li><p>初始化设备号、<code>class</code>、设备类型、父设备、设备名称等；</p>
</li>
</ul>
<p>那<code>drm_class</code>是在哪里创建的呢？<code>drm_class</code>是在<code>drm</code>驱动模块注册函数<code>drm_core_init</code>中创建的。</p>
<h5 id="6-1-2-drm-minor-get-slot"><a href="#6-1-2-drm-minor-get-slot" class="headerlink" title="6.1.2  drm_minor_get_slot"></a>6.1.2 <code> drm_minor_get_slot</code></h5><p>函数<code>drm_minor_get_slot</code>定义在<code>drivers/gpu/drm/drm_drv.c</code>;</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * DRM Minors</span></span><br><span class="line"><span class="comment"> * A DRM device can provide several char-dev interfaces on the DRM-Major. Each</span></span><br><span class="line"><span class="comment"> * of them is represented by a drm_minor object. Depending on the capabilities</span></span><br><span class="line"><span class="comment"> * of the device-driver, different interfaces are registered.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Minors can be accessed via dev-&gt;$minor_name. This pointer is either</span></span><br><span class="line"><span class="comment"> * NULL or a valid drm_minor pointer and stays valid as long as the device is</span></span><br><span class="line"><span class="comment"> * valid. This means, DRM minors have the same life-time as the underlying</span></span><br><span class="line"><span class="comment"> * device. However, this doesn&#x27;t mean that the minor is active. Minors are</span></span><br><span class="line"><span class="comment"> * registered and unregistered dynamically according to device-state.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> drm_minor **<span class="title function_">drm_minor_get_slot</span><span class="params">(<span class="keyword">struct</span> drm_device *dev,</span></span><br><span class="line"><span class="params">                                             <span class="type">unsigned</span> <span class="type">int</span> type)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="keyword">switch</span> (type) &#123;</span><br><span class="line">        <span class="keyword">case</span> DRM_MINOR_PRIMARY:</span><br><span class="line">                <span class="keyword">return</span> &amp;dev-&gt;primary;</span><br><span class="line">        <span class="keyword">case</span> DRM_MINOR_RENDER:</span><br><span class="line">                <span class="keyword">return</span> &amp;dev-&gt;render;</span><br><span class="line">        <span class="keyword">case</span> DRM_MINOR_ACCEL:</span><br><span class="line">                <span class="keyword">return</span> &amp;dev-&gt;accel;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">                BUG();</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="6-2-drm-gem-init"><a href="#6-2-drm-gem-init" class="headerlink" title="6.2 drm_gem_init"></a>6.2 <code>drm_gem_init</code></h4><p><code>drm_gem_init</code>定义在<code>drivers/gpu/drm/drm_gem.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_gem_init - Initialize the GEM device fields</span></span><br><span class="line"><span class="comment"> * @dev: drm_devic structure to initialize</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span></span><br><span class="line"><span class="title function_">drm_gem_init</span><span class="params">(<span class="keyword">struct</span> drm_device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_vma_offset_manager</span> *<span class="title">vma_offset_manager</span>;</span></span><br><span class="line"></span><br><span class="line">        mutex_init(&amp;dev-&gt;object_name_lock);</span><br><span class="line">        idr_init_base(&amp;dev-&gt;object_name_idr, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">        vma_offset_manager = drmm_kzalloc(dev, <span class="keyword">sizeof</span>(*vma_offset_manager),</span><br><span class="line">                                          GFP_KERNEL);</span><br><span class="line">        <span class="keyword">if</span> (!vma_offset_manager) &#123;</span><br><span class="line">                DRM_ERROR(<span class="string">&quot;out of memory\n&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> -ENOMEM;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        dev-&gt;vma_offset_manager = vma_offset_manager;</span><br><span class="line">        drm_vma_offset_manager_init(vma_offset_manager,</span><br><span class="line">                                    DRM_FILE_PAGE_OFFSET_START,</span><br><span class="line">                                    DRM_FILE_PAGE_OFFSET_SIZE);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> drmm_add_action(dev, drm_gem_init_release, <span class="literal">NULL</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="七、注册drm设备"><a href="#七、注册drm设备" class="headerlink" title="七、注册drm设备"></a>七、注册<code>drm</code>设备</h3><p><code>drm_dev_register</code>函数向内核注册一个<code>drm</code>设备，同时在用户空间创建<code>drm</code>设备节点<code>/dev/dri/card%d</code>，函数定义在<code>drivers/gpu/drm/drm_drv.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_dev_register - Register DRM device</span></span><br><span class="line"><span class="comment"> * @dev: Device to register</span></span><br><span class="line"><span class="comment"> * @flags: Flags passed to the driver&#x27;s .load() function</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Register the DRM device @dev with the system, advertise device to user-space</span></span><br><span class="line"><span class="comment"> * and start normal device operation. @dev must be initialized via drm_dev_init()</span></span><br><span class="line"><span class="comment"> * previously.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Never call this twice on any device!</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">NOTE:</span> To ensure backward compatibility with existing drivers method this</span></span><br><span class="line"><span class="comment"> * function calls the &amp;drm_driver.load method after registering the device</span></span><br><span class="line"><span class="comment"> * nodes, creating race conditions. Usage of the &amp;drm_driver.load methods is</span></span><br><span class="line"><span class="comment"> * therefore deprecated, drivers must perform all initialization before calling</span></span><br><span class="line"><span class="comment"> * drm_dev_register().</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * RETURNS:</span></span><br><span class="line"><span class="comment"> * 0 on success, negative error code on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drm_dev_register</span><span class="params">(<span class="keyword">struct</span> drm_device *dev, <span class="type">unsigned</span> <span class="type">long</span> flags)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_driver</span> *<span class="title">driver</span> =</span> dev-&gt;driver;</span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line">		</span><br><span class="line">    	<span class="comment">// 如果没有配置load,则校验drm模式配置</span></span><br><span class="line">        <span class="keyword">if</span> (!driver-&gt;load)</span><br><span class="line">                drm_mode_config_validate(dev);</span><br><span class="line"></span><br><span class="line">        WARN_ON(!dev-&gt;managed.final_kfree);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 如果需要全局互斥锁，则获取互斥锁</span></span><br><span class="line">        <span class="keyword">if</span> (drm_dev_needs_global_mutex(dev))</span><br><span class="line">                mutex_lock(&amp;drm_global_mutex);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 直接返回</span></span><br><span class="line">        ret = drm_minor_register(dev, DRM_MINOR_RENDER);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_minors;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 重点 注册dev-&gt;primary这个minor</span></span><br><span class="line">        ret = drm_minor_register(dev, DRM_MINOR_PRIMARY);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_minors;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 直接返回</span></span><br><span class="line">        ret = drm_minor_register(dev, DRM_MINOR_ACCEL);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_minors;</span><br><span class="line"></span><br><span class="line">        ret = create_compat_control_link(dev);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_minors;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 设备注册标志设置为true</span></span><br><span class="line">        dev-&gt;registered = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 如果定义了load，会先执行load</span></span><br><span class="line">        <span class="keyword">if</span> (driver-&gt;load) &#123;</span><br><span class="line">                ret = driver-&gt;load(dev, flags);</span><br><span class="line">                <span class="keyword">if</span> (ret)</span><br><span class="line">                        <span class="keyword">goto</span> err_minors;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (drm_core_check_feature(dev, DRIVER_MODESET))</span><br><span class="line">                drm_modeset_register_all(dev);</span><br><span class="line"></span><br><span class="line">        DRM_INFO(<span class="string">&quot;Initialized %s %d.%d.%d %s for %s on minor %d\n&quot;</span>,</span><br><span class="line">                 driver-&gt;name, driver-&gt;major, driver-&gt;minor,</span><br><span class="line">                 driver-&gt;patchlevel, driver-&gt;date,</span><br><span class="line">                 dev-&gt;dev ? dev_name(dev-&gt;dev) : <span class="string">&quot;virtual device&quot;</span>,</span><br><span class="line">                 dev-&gt;primary ? dev-&gt;primary-&gt;index : dev-&gt;accel-&gt;index);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">goto</span> out_unlock;</span><br><span class="line"></span><br><span class="line">err_minors:</span><br><span class="line">        remove_compat_control_link(dev);</span><br><span class="line">        drm_minor_unregister(dev, DRM_MINOR_ACCEL);</span><br><span class="line">        drm_minor_unregister(dev, DRM_MINOR_PRIMARY);</span><br><span class="line">        drm_minor_unregister(dev, DRM_MINOR_RENDER);</span><br><span class="line">out_unlock:</span><br><span class="line">    	<span class="comment">// 同理，释放互斥锁</span></span><br><span class="line">        <span class="keyword">if</span> (drm_dev_needs_global_mutex(dev))</span><br><span class="line">                mutex_unlock(&amp;drm_global_mutex);</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="7-1-drm-mode-config-validate"><a href="#7-1-drm-mode-config-validate" class="headerlink" title="7.1 drm_mode_config_validate"></a>7.1 <code>drm_mode_config_validate</code></h4><p><code>drm_mode_config_validate</code>函数用于校验<code>drm</code>模式配置，定义在<code>drivers/gpu/drm/drm_mode_config.c</code>；</p>
<details>
<summary>
  点击查看代码
</summary>


<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">drm_mode_config_validate</span><span class="params">(<span class="keyword">struct</span> drm_device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_encoder</span> *<span class="title">encoder</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_crtc</span> *<span class="title">crtc</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_plane</span> *<span class="title">plane</span>;</span></span><br><span class="line">        u32 primary_with_crtc = <span class="number">0</span>, cursor_with_crtc = <span class="number">0</span>;</span><br><span class="line">        <span class="type">unsigned</span> <span class="type">int</span> num_primary = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!drm_core_check_feature(dev, DRIVER_MODESET))</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">        drm_for_each_encoder(encoder, dev)</span><br><span class="line">                fixup_encoder_possible_clones(encoder);</span><br><span class="line"></span><br><span class="line">        drm_for_each_encoder(encoder, dev) &#123;</span><br><span class="line">                validate_encoder_possible_clones(encoder);</span><br><span class="line">                validate_encoder_possible_crtcs(encoder);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        drm_for_each_crtc(crtc, dev) &#123;</span><br><span class="line">                WARN(!crtc-&gt;primary, <span class="string">&quot;Missing primary plane on [CRTC:%d:%s]\n&quot;</span>,</span><br><span class="line">                     crtc-&gt;base.id, crtc-&gt;name);</span><br><span class="line"></span><br><span class="line">                WARN(crtc-&gt;cursor &amp;&amp; crtc-&gt;funcs-&gt;cursor_set,</span><br><span class="line">                     <span class="string">&quot;[CRTC:%d:%s] must not have both a cursor plane and a cursor_set func&quot;</span>,</span><br><span class="line">                     crtc-&gt;base.id, crtc-&gt;name);</span><br><span class="line">                WARN(crtc-&gt;cursor &amp;&amp; crtc-&gt;funcs-&gt;cursor_set2,</span><br><span class="line">                     <span class="string">&quot;[CRTC:%d:%s] must not have both a cursor plane and a cursor_set2 func&quot;</span>,</span><br><span class="line">                     crtc-&gt;base.id, crtc-&gt;name);</span><br><span class="line">                WARN(crtc-&gt;cursor &amp;&amp; crtc-&gt;funcs-&gt;cursor_move,</span><br><span class="line">                     <span class="string">&quot;[CRTC:%d:%s] must not have both a cursor plane and a cursor_move func&quot;</span>,</span><br><span class="line">                     crtc-&gt;base.id, crtc-&gt;name);</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (crtc-&gt;primary) &#123;</span><br><span class="line">                        WARN(!(crtc-&gt;primary-&gt;possible_crtcs &amp; drm_crtc_mask(crtc)),</span><br><span class="line">                             <span class="string">&quot;Bogus primary plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n&quot;</span>,</span><br><span class="line">                             crtc-&gt;primary-&gt;base.id, crtc-&gt;primary-&gt;name,</span><br><span class="line">                             crtc-&gt;base.id, crtc-&gt;name);</span><br><span class="line">                        WARN(primary_with_crtc &amp; drm_plane_mask(crtc-&gt;primary),</span><br><span class="line">                             <span class="string">&quot;Primary plane [PLANE:%d:%s] used for multiple CRTCs&quot;</span>,</span><br><span class="line">                             crtc-&gt;primary-&gt;base.id, crtc-&gt;primary-&gt;name);</span><br><span class="line">                        primary_with_crtc |= drm_plane_mask(crtc-&gt;primary);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (crtc-&gt;cursor) &#123;</span><br><span class="line">                        WARN(!(crtc-&gt;cursor-&gt;possible_crtcs &amp; drm_crtc_mask(crtc)),</span><br><span class="line">                             <span class="string">&quot;Bogus cursor plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n&quot;</span>,</span><br><span class="line">                             crtc-&gt;cursor-&gt;base.id, crtc-&gt;cursor-&gt;name,</span><br><span class="line">                             crtc-&gt;base.id, crtc-&gt;name);</span><br><span class="line">                        WARN(cursor_with_crtc &amp; drm_plane_mask(crtc-&gt;cursor),</span><br><span class="line">                             <span class="string">&quot;Cursor plane [PLANE:%d:%s] used for multiple CRTCs&quot;</span>,</span><br><span class="line">                             crtc-&gt;cursor-&gt;base.id, crtc-&gt;cursor-&gt;name);</span><br><span class="line">                        cursor_with_crtc |= drm_plane_mask(crtc-&gt;cursor);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        drm_for_each_plane(plane, dev) &#123;</span><br><span class="line">                <span class="keyword">if</span> (plane-&gt;type == DRM_PLANE_TYPE_PRIMARY)</span><br><span class="line">                        num_primary++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        WARN(num_primary != dev-&gt;mode_config.num_crtc,</span><br><span class="line">             <span class="string">&quot;Must have as many primary planes as there are CRTCs, but have %u primary planes and %u CRTCs&quot;</span>,</span><br><span class="line">             num_primary, dev-&gt;mode_config.num_crtc);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</details>

<h4 id="7-2-drm-minor-register"><a href="#7-2-drm-minor-register" class="headerlink" title="7.2 drm_minor_register"></a>7.2 <code>drm_minor_register</code></h4><p>在<code>drm_dev_register</code>函数中多次调用了<code>drm_minor_register</code>，那<code>drm_minor_register</code>函数是干嘛用的呢？</p>
<p>该函数的目的主要是用来注册<code>drm_minor</code>的，会在<code>/dev/dri</code>目录下创建<code>card%d</code>设备节点；函数定义在<code>drivers/gpu/drm/drm_drv.c</code>;</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_minor_register</span><span class="params">(<span class="keyword">struct</span> drm_device *dev, <span class="type">unsigned</span> <span class="type">int</span> type)</span> <span class="comment">// type以DRM_MINOR_PRIMAR为例</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">minor</span>;</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> flags;</span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        DRM_DEBUG(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// dev-&gt;primary</span></span><br><span class="line">        minor = *drm_minor_get_slot(dev, type);</span><br><span class="line">        <span class="keyword">if</span> (!minor)  <span class="comment">// 针对于DRM_MINOR_RENDER、DRM_MINOR_ACCEL会直接返回的</span></span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (minor-&gt;type == DRM_MINOR_ACCEL) &#123; <span class="comment">// 不会进入</span></span><br><span class="line">                accel_debugfs_init(minor, minor-&gt;index);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            	<span class="comment">// 初始化debugfs</span></span><br><span class="line">                ret = drm_debugfs_init(minor, minor-&gt;index, drm_debugfs_root);</span><br><span class="line">                <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                        DRM_ERROR(<span class="string">&quot;DRM: Failed to initialize /sys/kernel/debug/dri.\n&quot;</span>);</span><br><span class="line">                        <span class="keyword">goto</span> err_debugfs;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 注册minor-&gt;kdev设备，这样在模块加载的时候，udev daemon就会自动为我们创建设备节点文件/dev/dri/card%d</span></span><br><span class="line">        ret = device_add(minor-&gt;kdev);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_debugfs;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* replace NULL with @minor so lookups will succeed from now on */</span></span><br><span class="line">        <span class="keyword">if</span> (minor-&gt;type == DRM_MINOR_ACCEL) &#123;  <span class="comment">// 不会进入</span></span><br><span class="line">                accel_minor_replace(minor, minor-&gt;index);</span><br><span class="line">        &#125; <span class="keyword">else</span> </span><br><span class="line">            	<span class="comment">// 获取自旋锁+关中断</span></span><br><span class="line">                spin_lock_irqsave(&amp;drm_minor_lock, flags);</span><br><span class="line">    			<span class="comment">// 将minor与minor-&gt;index这个id关联起来，这样就可以通过id查找到minor</span></span><br><span class="line">                idr_replace(&amp;drm_minors_idr, minor, minor-&gt;index);</span><br><span class="line">                <span class="comment">// 释放自旋锁+开中断</span></span><br><span class="line">                spin_unlock_irqrestore(&amp;drm_minor_lock, flags);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        DRM_DEBUG(<span class="string">&quot;new minor registered %d\n&quot;</span>, minor-&gt;index);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_debugfs:</span><br><span class="line">        drm_debugfs_cleanup(minor);</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>主要进行了如下操作：</p>
<ul>
<li>调用<code>drm_minor_get_slot</code>获取<code>dev</code>-&gt;<code>primary</code>这个<code>minor</code>；</li>
<li>调用<code>drm_debugfs_init</code>进行<code>debugfs</code>的初始化工作；</li>
<li>调用<code>device_add</code>注册<code>minor-&gt;kdev</code>设备，这样在模块加载的时候，<code>udev daemon</code>就会自动为我们创建设备节点文件<code>/dev/dri/card%d</code>；</li>
<li>调用<code>idr_replace</code>将<code>minor</code>与<code>minor</code>-&gt;<code>index</code>这个<code>id</code>关联起来，这样就可以在基数树中通过<code>id</code>查找到<code>minor</code>；</li>
</ul>
<h5 id="7-2-1-drm-minor-get-slot"><a href="#7-2-1-drm-minor-get-slot" class="headerlink" title="7.2.1 drm_minor_get_slot"></a>7.2.1 <code>drm_minor_get_slot</code></h5><p>通过<code>drm_minor_get_slot</code>获取<code>drm</code>-&gt;<code>primary</code>这个<code>minor</code>。</p>
<h5 id="7-2-2-drm-debugfs-init"><a href="#7-2-2-drm-debugfs-init" class="headerlink" title="7.2.2 drm_debugfs_init"></a>7.2.2 <code>drm_debugfs_init</code></h5><p>调用<code>drm_debugfs_init</code>进行<code>debugfs</code>的初始化工作，函数定义在<code>drivers/gpu/drm/drm_debugfs.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">drm_debugfs_init</span><span class="params">(<span class="keyword">struct</span> drm_minor *minor, <span class="type">int</span> minor_id,</span></span><br><span class="line"><span class="params">                     <span class="keyword">struct</span> dentry *root)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span> =</span> minor-&gt;dev;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_entry</span> *<span class="title">entry</span>, *<span class="title">tmp</span>;</span></span><br><span class="line">        <span class="type">char</span> name[<span class="number">64</span>];</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化debugfs_list链表</span></span><br><span class="line">        INIT_LIST_HEAD(&amp;minor-&gt;debugfs_list);</span><br><span class="line">	    <span class="comment">// 初始化互斥锁</span></span><br><span class="line">        mutex_init(&amp;minor-&gt;debugfs_lock);</span><br><span class="line">    	<span class="comment">// 初始化name</span></span><br><span class="line">        <span class="built_in">sprintf</span>(name, <span class="string">&quot;%d&quot;</span>, minor_id);</span><br><span class="line">    	<span class="comment">// 在debugfs以name命名的目录，父目录为drm_debugfs_root</span></span><br><span class="line">        minor-&gt;debugfs_root = debugfs_create_dir(name, root);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 遍历drm_debugfs_list数组，为每个元素(struct drm_debugfs_info)创建struct drm_debugfs_entry，并添加到dev-&gt;debugfs_list</span></span><br><span class="line">        drm_debugfs_add_files(minor-&gt;dev, drm_debugfs_list, DRM_DEBUGFS_ENTRIES);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (drm_drv_uses_atomic_modeset(dev)) &#123;</span><br><span class="line">                drm_atomic_debugfs_init(minor);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (drm_core_check_feature(dev, DRIVER_MODESET)) &#123;</span><br><span class="line">                drm_framebuffer_debugfs_init(minor);</span><br><span class="line"></span><br><span class="line">                drm_client_debugfs_init(minor);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 如果指定了debugfs_init回调函数，则执行</span></span><br><span class="line">        <span class="keyword">if</span> (dev-&gt;driver-&gt;debugfs_init)</span><br><span class="line">                dev-&gt;driver-&gt;debugfs_init(minor);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 遍历dev-&gt;debugfs_list链表</span></span><br><span class="line">        list_for_each_entry_safe(entry, tmp, &amp;dev-&gt;debugfs_list, <span class="built_in">list</span>) &#123;</span><br><span class="line">            	<span class="comment">// 在debugfs创建以entry-&gt;file.name命名的文件，位于/sys/kernel/debug/dri/$&#123;name&#125;目录下</span></span><br><span class="line">                debugfs_create_file(entry-&gt;file.name, <span class="number">0444</span>,</span><br><span class="line">                                    minor-&gt;debugfs_root, entry, &amp;drm_debugfs_entry_fops);</span><br><span class="line">                list_del(&amp;entry-&gt;<span class="built_in">list</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>drm_debugfs_root</code>在<code>drm_core_init</code>函数中被初始化，定义在<code>drivers/gpu/drm/drm_drv.c</code>，该函数会在<code>/sys/kernel/debug</code>下创建<code>dri</code>目录；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">drm_core_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;		</span><br><span class="line">		......</span><br><span class="line">        <span class="comment">// 在/sys/kernel/debug下创建dri目录</span></span><br><span class="line">        drm_debugfs_root = debugfs_create_dir(<span class="string">&quot;dri&quot;</span>, <span class="literal">NULL</span>);</span><br><span class="line">		......           </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>drm_debugfs_list</code>是一个全局数组，定义在<code>drivers/gpu/drm/drm_debugfs.c</code>，内容如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/***************************************************</span></span><br><span class="line"><span class="comment"> * Initialization, etc.</span></span><br><span class="line"><span class="comment"> **************************************************/</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_name_info</span><span class="params">(<span class="keyword">struct</span> seq_file *m, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_entry</span> *<span class="title">entry</span> =</span> m-&gt;private;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span> =</span> entry-&gt;dev;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_master</span> *<span class="title">master</span>;</span></span><br><span class="line"></span><br><span class="line">        mutex_lock(&amp;dev-&gt;master_mutex);</span><br><span class="line">        master = dev-&gt;master;</span><br><span class="line">        seq_printf(m, <span class="string">&quot;%s&quot;</span>, dev-&gt;driver-&gt;name);</span><br><span class="line">        <span class="keyword">if</span> (dev-&gt;dev)</span><br><span class="line">                seq_printf(m, <span class="string">&quot; dev=%s&quot;</span>, dev_name(dev-&gt;dev));</span><br><span class="line">        <span class="keyword">if</span> (master &amp;&amp; master-&gt;unique)</span><br><span class="line">                seq_printf(m, <span class="string">&quot; master=%s&quot;</span>, master-&gt;unique);</span><br><span class="line">        <span class="keyword">if</span> (dev-&gt;unique)</span><br><span class="line">                seq_printf(m, <span class="string">&quot; unique=%s&quot;</span>, dev-&gt;unique);</span><br><span class="line">        seq_printf(m, <span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        mutex_unlock(&amp;dev-&gt;master_mutex);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_clients_info</span><span class="params">(<span class="keyword">struct</span> seq_file *m, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_entry</span> *<span class="title">entry</span> =</span> m-&gt;private;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span> =</span> entry-&gt;dev;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_file</span> *<span class="title">priv</span>;</span></span><br><span class="line">        <span class="type">kuid_t</span> uid;</span><br><span class="line"></span><br><span class="line">        seq_printf(m,</span><br><span class="line">                   <span class="string">&quot;%20s %5s %3s master a %5s %10s\n&quot;</span>,</span><br><span class="line">                   <span class="string">&quot;command&quot;</span>,</span><br><span class="line">                   <span class="string">&quot;pid&quot;</span>,</span><br><span class="line">                   <span class="string">&quot;dev&quot;</span>,</span><br><span class="line">                   <span class="string">&quot;uid&quot;</span>,</span><br><span class="line">                   <span class="string">&quot;magic&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* dev-&gt;filelist is sorted youngest first, but we want to present</span></span><br><span class="line"><span class="comment">         * oldest first (i.e. kernel, servers, clients), so walk backwardss.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        mutex_lock(&amp;dev-&gt;filelist_mutex);</span><br><span class="line">        list_for_each_entry_reverse(priv, &amp;dev-&gt;filelist, lhead) &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">task_struct</span> *<span class="title">task</span>;</span></span><br><span class="line">                <span class="type">bool</span> is_current_master = drm_is_current_master(priv);</span><br><span class="line"></span><br><span class="line">                rcu_read_lock(); <span class="comment">/* locks pid_task()-&gt;comm */</span></span><br><span class="line">                task = pid_task(priv-&gt;pid, PIDTYPE_PID);</span><br><span class="line">                uid = task ? __task_cred(task)-&gt;euid : GLOBAL_ROOT_UID;</span><br><span class="line">                seq_printf(m, <span class="string">&quot;%20s %5d %3d   %c    %c %5d %10u\n&quot;</span>,</span><br><span class="line">                           task ? task-&gt;comm : <span class="string">&quot;&lt;unknown&gt;&quot;</span>,</span><br><span class="line">                           pid_vnr(priv-&gt;pid),</span><br><span class="line">                           priv-&gt;minor-&gt;index,</span><br><span class="line">                           is_current_master ? <span class="string">&#x27;y&#x27;</span> : <span class="string">&#x27;n&#x27;</span>,</span><br><span class="line">                           priv-&gt;authenticated ? <span class="string">&#x27;y&#x27;</span> : <span class="string">&#x27;n&#x27;</span>,</span><br><span class="line">                           from_kuid_munged(seq_user_ns(m), uid),</span><br><span class="line">                           priv-&gt;magic);</span><br><span class="line">                rcu_read_unlock();</span><br><span class="line">        &#125;</span><br><span class="line">        mutex_unlock(&amp;dev-&gt;filelist_mutex);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_gem_one_name_info</span><span class="params">(<span class="type">int</span> id, <span class="type">void</span> *ptr, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span> =</span> ptr;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">seq_file</span> *<span class="title">m</span> =</span> data;</span><br><span class="line"></span><br><span class="line">        seq_printf(m, <span class="string">&quot;%6d %8zd %7d %8d\n&quot;</span>,</span><br><span class="line">                   obj-&gt;name, obj-&gt;size,</span><br><span class="line">                   obj-&gt;handle_count,</span><br><span class="line">                   kref_read(&amp;obj-&gt;refcount));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">drm_gem_name_info</span><span class="params">(<span class="keyword">struct</span> seq_file *m, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_entry</span> *<span class="title">entry</span> =</span> m-&gt;private;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span> =</span> entry-&gt;dev;</span><br><span class="line"></span><br><span class="line">        seq_printf(m, <span class="string">&quot;  name     size handles refcount\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">        mutex_lock(&amp;dev-&gt;object_name_lock);</span><br><span class="line">        idr_for_each(&amp;dev-&gt;object_name_idr, drm_gem_one_name_info, m);</span><br><span class="line">        mutex_unlock(&amp;dev-&gt;object_name_lock);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_debugfs_info</span> <span class="title">drm_debugfs_list</span>[] =</span> &#123;</span><br><span class="line">        &#123;<span class="string">&quot;name&quot;</span>, drm_name_info, <span class="number">0</span>&#125;,     <span class="comment">// 依次为name、show、data</span></span><br><span class="line">        &#123;<span class="string">&quot;clients&quot;</span>, drm_clients_info, <span class="number">0</span>&#125;,</span><br><span class="line">        &#123;<span class="string">&quot;gem_names&quot;</span>, drm_gem_name_info, DRIVER_GEM&#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p><code>drm_minor_register</code>函数会遍历<code>drm_debugfs_list</code>数组，依次为每个成员在<code>/sys/kernel/debug/dri/$&#123;name&#125;</code>目录下创建以<code>name</code>为名称的文件，在对文件进行打开操作时会执行相应的<code>show</code>方法；</p>
<p>比如，在<code>NanoPC-T4</code>开发板运行如下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">root@rk3399:~# ll /sys/kernel/debug/dri/</span><br><span class="line">drwxr-xr-x  5 root root 0 Jan  1  1970 0/</span><br><span class="line">drwxr-xr-x  2 root root 0 Jan  1  1970 1/</span><br><span class="line">drwxr-xr-x  2 root root 0 Jan  1  1970 128/</span><br><span class="line">root@rk3399:~# ll /sys/kernel/debug/dri/0/      </span><br><span class="line">drwxr-xr-x 2 root root 0 Jan  1  1970 HDMI-A-1/</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 clients</span><br><span class="line">drwxr-xr-x 3 root root 0 Jan  1  1970 crtc-0/</span><br><span class="line">drwxr-xr-x 3 root root 0 Jan  1  1970 crtc-1/</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 framebuffer</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 gem_names</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 internal_clients</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 name</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 state</span><br><span class="line">root@rk3399:~# ll /sys/kernel/debug/dri/1      </span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 clients</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 gem_names</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 name</span><br><span class="line">root@rk3399:~# ll /sys/kernel/debug/dri/128/</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 clients</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 gem_names</span><br><span class="line">-r--r--r-- 1 root root 0 Jan  1  1970 name</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>当调用<code>drm_minor_register(dev,xxx)</code>时，如果<code>minor</code>-&gt;<code>index</code>&#x3D;0，在会创建<code>/sys/kernel/debug/dri/0 </code>目录以及文件<code>clients</code>、<code>gem_names</code>、<code>name</code>；</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">root@rk3399:~# cat /sys/kernel/debug/dri/0/name</span><br><span class="line">rockchip dev=display-subsystem master=display-subsystem unique=display-subsystem</span><br><span class="line">root@rk3399:~# cat /sys/kernel/debug/dri/0/clients</span><br><span class="line">             command   pid dev master a   uid      magic</span><br><span class="line">      systemd-logind  3657   0   y    y     0          0</span><br><span class="line">                Xorg  4148   0   n    y     0          1</span><br><span class="line">root@rk3399:~# cat /sys/kernel/debug/dri/0/gem_names</span><br><span class="line">  name     size handles refcount</span><br></pre></td></tr></table></figure>

<h5 id="7-2-3-device-add"><a href="#7-2-3-device-add" class="headerlink" title="7.2.3 device_add"></a>7.2.3 <code>device_add</code></h5><p>调用<code>device_add(minor-&gt;kdev)</code>注册<code>minor</code>-&gt;<code>kdev</code>设备，这样在模块加载的时候，<code>udev daemon</code>就会自动为我们创建设备节点文件<code>/dev/dri/card%d</code>，其中<code>minor</code>-&gt;<code>kdev</code>设备的<code>class</code>被设置为了<code>drm_class</code>；</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">root@rk3399:~# ll /dev/dri/card0</span><br><span class="line">crw-rw---- 1 root video 226, 0 Sep  9 22:10 /dev/dri/card0</span><br><span class="line">root@rk3399:~# ll /sys/class/drm/card0</span><br><span class="line">lrwxrwxrwx 1 root root 0 Mar 15 23:04 /sys/class/drm/card0 -&gt; ../../devices/platform/display-subsystem/drm/card0/</span><br><span class="line">root@rk3399:~# ll /sys/class/drm/card0/</span><br><span class="line">card0-HDMI-A-1/ device/         subsystem/</span><br><span class="line">dev             power/          uevent</span><br></pre></td></tr></table></figure>

<h3 id="八、drm-mode-config-init"><a href="#八、drm-mode-config-init" class="headerlink" title="八、drm_mode_config_init"></a>八、<code>drm_mode_config_init</code></h3><p><code>drm_mode_config_init</code>用于初始化<code>drm_device</code>的<code>mode_config</code>结构体，函数定义在<code>include/drm/drm_mode_config.h</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_mode_config_init - DRM mode_configuration structure initialization</span></span><br><span class="line"><span class="comment"> * @dev: DRM device</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This is the unmanaged version of drmm_mode_config_init() for drivers which</span></span><br><span class="line"><span class="comment"> * still explicitly call drm_mode_config_cleanup().</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">FIXME:</span> This function is deprecated and drivers should be converted over to</span></span><br><span class="line"><span class="comment"> * drmm_mode_config_init().</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">int</span> <span class="title function_">drm_mode_config_init</span><span class="params">(<span class="keyword">struct</span> drm_device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="keyword">return</span> drmm_mode_config_init(dev);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>drmm_mode_config_init</code>定义在<code>drivers/gpu/drm/drm_mode_config.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drmm_mode_config_init - managed DRM mode_configuration structure</span></span><br><span class="line"><span class="comment"> *      initialization</span></span><br><span class="line"><span class="comment"> * @dev: DRM device</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Initialize @dev&#x27;s mode_config structure, used for tracking the graphics</span></span><br><span class="line"><span class="comment"> * configuration of @dev.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Since this initializes the modeset locks, no locking is possible. Which is no</span></span><br><span class="line"><span class="comment"> * problem, since this should happen single threaded at init time. It is the</span></span><br><span class="line"><span class="comment"> * driver&#x27;s problem to ensure this guarantee.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Cleanup is automatically handled through registering drm_mode_config_cleanup</span></span><br><span class="line"><span class="comment"> * with drmm_add_action().</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns: 0 on success, negative error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drmm_mode_config_init</span><span class="params">(<span class="keyword">struct</span> drm_device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        mutex_init(&amp;dev-&gt;mode_config.mutex);</span><br><span class="line">        drm_modeset_lock_init(&amp;dev-&gt;mode_config.connection_mutex);</span><br><span class="line">        mutex_init(&amp;dev-&gt;mode_config.idr_mutex);</span><br><span class="line">        mutex_init(&amp;dev-&gt;mode_config.fb_lock);</span><br><span class="line">        mutex_init(&amp;dev-&gt;mode_config.blob_lock);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.fb_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.crtc_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.connector_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.encoder_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.property_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.property_blob_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.plane_list);</span><br><span class="line">        INIT_LIST_HEAD(&amp;dev-&gt;mode_config.privobj_list);</span><br><span class="line">        idr_init_base(&amp;dev-&gt;mode_config.object_idr, <span class="number">1</span>);</span><br><span class="line">        idr_init_base(&amp;dev-&gt;mode_config.tile_idr, <span class="number">1</span>);</span><br><span class="line">        ida_init(&amp;dev-&gt;mode_config.connector_ida);</span><br><span class="line">        spin_lock_init(&amp;dev-&gt;mode_config.connector_list_lock);</span><br><span class="line"></span><br><span class="line">        init_llist_head(&amp;dev-&gt;mode_config.connector_free_list);</span><br><span class="line">        INIT_WORK(&amp;dev-&gt;mode_config.connector_free_work, drm_connector_free_work_fn);</span><br><span class="line"></span><br><span class="line">        ret = drm_mode_create_standard_properties(dev);</span><br><span class="line">        <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                drm_mode_config_cleanup(dev);</span><br><span class="line">                <span class="keyword">return</span> ret;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Just to be sure */</span></span><br><span class="line">        dev-&gt;mode_config.num_fb = <span class="number">0</span>;</span><br><span class="line">        dev-&gt;mode_config.num_connector = <span class="number">0</span>;</span><br><span class="line">        dev-&gt;mode_config.num_crtc = <span class="number">0</span>;</span><br><span class="line">        dev-&gt;mode_config.num_encoder = <span class="number">0</span>;</span><br><span class="line">        dev-&gt;mode_config.num_total_plane = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (IS_ENABLED(CONFIG_LOCKDEP)) &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">drm_modeset_acquire_ctx</span> <span class="title">modeset_ctx</span>;</span></span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">ww_acquire_ctx</span> <span class="title">resv_ctx</span>;</span></span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">dma_resv</span> <span class="title">resv</span>;</span></span><br><span class="line">                <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">                dma_resv_init(&amp;resv);</span><br><span class="line"></span><br><span class="line">                drm_modeset_acquire_init(&amp;modeset_ctx, <span class="number">0</span>);</span><br><span class="line">                ret = drm_modeset_lock(&amp;dev-&gt;mode_config.connection_mutex,</span><br><span class="line">                                       &amp;modeset_ctx);</span><br><span class="line">                <span class="keyword">if</span> (ret == -EDEADLK)</span><br><span class="line">                        ret = drm_modeset_backoff(&amp;modeset_ctx);</span><br><span class="line"></span><br><span class="line">                ww_acquire_init(&amp;resv_ctx, &amp;reservation_ww_class);</span><br><span class="line">                ret = dma_resv_lock(&amp;resv, &amp;resv_ctx);</span><br><span class="line">                <span class="keyword">if</span> (ret == -EDEADLK)</span><br><span class="line">                        dma_resv_lock_slow(&amp;resv, &amp;resv_ctx);</span><br><span class="line"></span><br><span class="line">                dma_resv_unlock(&amp;resv);</span><br><span class="line">                ww_acquire_fini(&amp;resv_ctx);</span><br><span class="line"></span><br><span class="line">                drm_modeset_drop_locks(&amp;modeset_ctx);</span><br><span class="line">                drm_modeset_acquire_fini(&amp;modeset_ctx);</span><br><span class="line">                dma_resv_fini(&amp;resv);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> drmm_add_action_or_reset(dev, drm_mode_config_init_release,</span><br><span class="line">                                        <span class="literal">NULL</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="九、drm-xxx-init"><a href="#九、drm-xxx-init" class="headerlink" title="九、drm_xxx_init"></a>九、<code>drm_xxx_init</code></h3><p><code>drm_xxx_init</code> 则分别用于创建 <code>plane</code>、<code>crtc</code>、<code>encoder</code>、<code>connector</code> 这4个 <code>drm_mode_object</code>。</p>
<p>具体实现函数<code>drm_universal_plane_init</code>、<code>drm_crtc_init_with_planes</code>、<code>drm_encoder_init</code>、<code>drm_connector_init</code>我们在后面章节单独介绍。</p>
<h3 id="十、总结"><a href="#十、总结" class="headerlink" title="十、总结"></a>十、总结</h3><p>下面我们使用一张图来将<code>DRM core</code>模块入口、<code>drm</code>设备初始化、<code>drm</code>设备注册等流程整合起来；</p>
<p><img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309101705583.svg"></p>
<p><strong>参考文章</strong></p>
<p><strong>[1] <a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/category_9281458.html"><code>DRM (Direct Rendering Manager</code>)</a></strong></p>
<p><strong>[2] <a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Direct_Rendering_Manager"><code>Wiki: Direct Rendering Manager</code></a></strong></p>
<p><strong>[3] <a target="_blank" rel="noopener" href="http://www.wowotech.net/linux_kenrel/dri_overview.html"><code>Linux graphic subsystem(2)_DRI</code>介绍</a></strong></p>
<p><strong>[4] <a target="_blank" rel="noopener" href="https://events.static.linuxfound.org/sites/events/files/slides/brezillon-drm-kms.pdf"><code>The DRM/KMS subsystem from a newbie’s point of view</code></a></strong></p>
<p><strong>[5] <a target="_blank" rel="noopener" href="https://www.cnblogs.com/shoemaker/p/linux_graphics01.html"><code>Linux</code>环境下的图形系统和<code>AMD R600</code>显卡编程(1)</a></strong></p>
<p><strong>[6] <a target="_blank" rel="noopener" href="https://blog.csdn.net/dearsq/article/details/78394388"><code>Linux DRM</code>（二）基本概念和特性</a></strong></p>
<p><strong>[7] <a target="_blank" rel="noopener" href="https://events.static.linuxfound.org/sites/events/files/slides/brezillon-drm-kms.pdf"><code>The DRM/KMS subsystem from a newbie’s point of view</code></a></strong></p>
<p><strong>[8] <a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_41709234/article/details/129472180"><code>DRM</code>驱动概念、组成、框架、源码分析</a></strong></p>
<p><strong>[9] <a target="_blank" rel="noopener" href="https://blog.csdn.net/zichuanning520/article/details/127047436"><code>linux</code>驱动系列学习之<code>DRM</code>（十）</a></strong></p>
<p><strong>[10] <a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/article/details/89810355"><code>DRM</code>驱动程序开发（开篇）</a></strong></p>
<p><strong>[11] <a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/article/details/105180621"><code>DRM</code>驱动程序开发（<code>VKMS</code>）</a></strong></p>
<p><strong>[12] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/92682047"><code>MIPI</code>自学笔记</a></strong></p>
<p><strong>[13] <a target="_blank" rel="noopener" href="https://blog.csdn.net/ytfy339784578/article/details/104557569"><code>DRM</code>的<code>GEM</code></a></strong></p>
<p><strong>[14] <a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/article/details/108655052"><code>DRM</code> 驱动<code>mmap</code>详解：（二）<code>CMA Helper</code></a></strong></p>
<p><strong>[15] <a target="_blank" rel="noopener" href="https://docs.kernel.org/gpu/drm-internals.html"><code>linux kernel DRM Internals</code></a></strong></p>
<p><strong>[16] <a target="_blank" rel="noopener" href="https://docs.kernel.org/gpu/drm-mm.html#gem-initialization"><code>linux gem initialization</code></a></strong></p>

        
      </div>

         
    </div>
    
     
  </div>
  
    
<nav id="article-nav">
  <a class="article-nav-btn left "
    
      href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/"
      title=""
     >
    <i class="fa-solid fa-angle-left"></i>
    <p class="title-text">
      
        (No Title)
        
    </p>
  </a>
  <a class="article-nav-btn right "
    
      href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%20plane/"
      title=""
     >

    <p class="title-text">
      
        (No Title)
        
    </p>
    <i class="fa-solid fa-angle-right"></i>
  </a>
</nav>


  
</article>

 
    </div>
    <div id="footer-wrapper">
      <footer id="footer">
  
  <div id="footer-info" class="inner">
    
    &copy; 2023 Your Name<br>
    Powered by <a href="https://hexo.io/" target="_blank">Hexo</a> & Theme <a target="_blank" rel="noopener" href="https://github.com/saicaca/hexo-theme-vivia">Vivia</a>
  </div>
</footer>

    </div>
    <div class="back-to-top-wrapper">
    <button id="back-to-top-btn" class="back-to-top-btn hide" onclick="topFunction()">
        <i class="fa-solid fa-angle-up"></i>
    </button>
</div>

<script>
    function topFunction() {
        window.scroll({ top: 0, behavior: 'smooth' });
    }
    let btn = document.getElementById('back-to-top-btn');
    function scrollFunction() {
        if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
            btn.classList.remove('hide')
        } else {
            btn.classList.add('hide')
        }
    }
    window.onscroll = function() {
        scrollFunction();
    }
</script>

  </div>
  <script src="/blog/js/light-dark-switch.js"></script>
</body>
</html>
